以下工会(不含AAA或BBB):
union AAA bpf_attr {
struct { /* Used by BPF_MAP_CREATE */
uint32_t map_type;
uint32_t key_size; /* size of key in bytes */
uint32_t value_size; /* size of value in bytes */
uint32_t max_entries; /* maximum number of entries
in a map */
};
struct { /* Used by BPF_MAP_*_ELEM and BPF_MAP_GET_NEXT_KEY commands */
uint32_t map_fd;
uint64_t alignas(8) key;
union {
uint64_t alignas(8) value;
uint64_t alignas(8) next_key;
};
uint64_t flags;
};
struct { /* Used by BPF_PROG_LOAD */
uint32_t prog_type;
uint32_t insn_cnt;
uint64_t alignas(8) insns; /* 'const struct bpf_insn *' */
uint64_t alignas(8) license; /* 'const char *' */
uint32_t log_level; /* verbosity level of verifier */
uint32_t log_size; /* size of user buffer */
uint64_t alignas(8) log_buf; /* user supplied 'char *'
buffer */
uint32_t kern_version;
/* checked when prog_type=kprobe
(since Linux 4.1) */
};
} BBB;如果我把_Alignas(8)放在AAA或BBB上有什么区别(如果有效的话还有其他位置)?标准似乎没有具体说明。前者之间有什么区别吗?还是对[[gnu::aligned(8)]]做同样的事情?GCC确实指出了一些不同之处,但我不明白其中的文字:
在
中,属性说明符跟随结束大括号,它们被认为与定义的结构、联合或枚举类型有关,而不是与类型说明符出现在其中的任何封闭声明有关,并且定义的类型直到属性说明符之后才完成。
编辑:
经过一些测试后,似乎(但一点也不确定):
union alignas(N) u {
...
} v;上述规定不合法。
union u {
...
} alignas(N) v;以上仅仅是合法的,因为有一个变量声明。它应相当于:
union u {
...
};
union u alignas(N) v;union [[gnu::aligned(8)]] u {
...
};以上似乎是合法的,不需要变量声明。
union u {
...
} [[gnu::aligned(8)]] v;上面的内容似乎被忽略了(有警告),但是我不明白为什么;文本说它是允许的,即使它不是首选的版本。
还有一件奇怪的事情:如果使用C2x语法而不是使用__attribute__((aligned(8))),最后一个表单不会触发警告,顺便说一句,__attribute__((aligned(8)))是Linux在其源代码中使用的表单。
我可以测试更多的组合,但这是一个指数问题,理论上的答案似乎更合适。
发布于 2021-05-04 10:13:00
根据标准和GNU文档,我不知道理论上的答案是什么,因为它们不是很详细,但是这里有一个广泛的实验答案。
为了我的实验,我写了以下文件:
align.c
#include <stdalign.h>
#include <stdio.h>
struct s {
int a;
long b;
char c;
} s_, s__;
__attribute__((aligned(16))) struct t {
int a;
long b;
char c;
} t_, t__;
alignas(16) struct tt {
int a;
long b;
char c;
} tt_, tt__;
[[gnu::aligned(16)]] struct ttt {
int a;
long b;
char c;
} ttt_, ttt__;
struct __attribute__((aligned(16))) u {
int a;
long b;
char c;
} u_, u__;
/* error: expected ‘{’ before ‘_Alignas’
struct alignas(16) uu {
int a;
long b;
char c;
} uu_, uu__;
*/
struct [[gnu::aligned(16)]] uuu {
int a;
long b;
char c;
} uuu_, uuu__;
/* error: expected identifier or ‘(’ before ‘{’ token
struct v __attribute__((aligned(16))) {
int a;
long b;
char c;
} v_, v_;
*/
/* error: expected identifier or ‘(’ before ‘{’ token
struct vv alignas(16) {
int a;
long b;
char c;
} vv_, vv__;
*/
// warning: ignoring attributes applied to ‘struct vvv’ after definition [-Wattributes]
/* error: expected identifier or ‘(’ before ‘{’ token
struct vvv [[gnu::aligned(16)]] {
int a;
long b;
char c;
} vvv_, vvv__;
*/
struct w {
int a;
long b;
char c;
} __attribute__((aligned(16))) w_, w__;
struct ww {
int a;
long b;
char c;
} alignas(16) ww_, ww__;
// warning: ignoring attributes applied to ‘struct www’ after definition [-Wattributes]
struct www {
int a;
long b;
char c;
} [[gnu::aligned(16)]] www_, www__;
struct x {
int a;
long b;
char c;
} x_ __attribute__((aligned(16))), x__;
/* error: expected ‘;’ before ‘_Alignas’
struct xx {
int a;
long b;
char c;
} xx_ alignas(16), xx__;
*/
struct xxx {
int a;
long b;
char c;
} xxx_ [[gnu::aligned(16)]], xxx__;
struct y {
int a;
long b;
char c;
} y_, __attribute__((aligned(16))) y__;
/* error: expected identifier or ‘(’ before ‘_Alignas’
struct yy {
int a;
long b;
char c;
} yy_, alignas(16) yy__;
*/
/* error: expected identifier or ‘(’ before ‘[’ token
struct yyy {
int a;
long b;
char c;
} yyy_, [[gnu::aligned(16)]] yyy__;
*/
struct z {
int a;
long b;
char c;
} z_, z__ __attribute__((aligned(16)));
/* error: expected ‘=’, ‘,’, ‘;’, ‘asm’ or ‘__attribute__’ before ‘_Alignas’
struct zz {
int a;
long b;
char c;
} zz_, zz__ alignas(16);
*/
struct zzz {
int a;
long b;
char c;
} zzz_, zzz__ [[gnu::aligned(16)]];
int main(void)
{
printf("s: %2zu; s_: %2zu; s__: %2zu\n\n", alignof(struct s), alignof(s_), alignof(s__));
printf("t: %2zu; t_: %2zu; t__: %2zu\n", alignof(struct t), alignof(t_), alignof(t__));
printf("tt: %2zu; tt_: %2zu; tt__: %2zu\n", alignof(struct tt), alignof(tt_), alignof(tt__));
printf("ttt: %2zu; ttt_: %2zu; ttt__: %2zu\n\n", alignof(struct ttt), alignof(ttt_), alignof(ttt__));
printf("u: %2zu; u_: %2zu; u__: %2zu\n", alignof(struct u), alignof(u_), alignof(u__));
puts("uu: -");// printf("uu: %2zu; uu_: %2zu; uu__: %2zu\n", alignof(struct uu), alignof(uu_), alignof(uu__));
printf("uuu: %2zu; uuu_: %2zu; uuu__: %2zu\n\n", alignof(struct uuu), alignof(uuu_), alignof(uuu__));
puts("v: -");// printf("v: %2zu; v_: %2zu; v__: %2zu\n", alignof(struct v), alignof(v_), alignof(v__));
puts("vv: -");// printf("vv: %2zu; vv_: %2zu; vv__: %2zu\n", alignof(struct vv), alignof(vv_), alignof(vv__));
puts("vvv: -\n");// printf("vvv: %2zu; vvv_: %2zu; vvv__: %2zu\n", alignof(struct vvv), alignof(vvv_), alignof(vvv__));
printf("w: %2zu; w_: %2zu; w__: %2zu\n", alignof(struct w), alignof(w_), alignof(w__));
printf("ww: %2zu; ww_: %2zu; ww__: %2zu\n", alignof(struct ww), alignof(ww_), alignof(ww__));
printf("www: %2zu; www_: %2zu; www__: %2zu\n\n", alignof(struct www), alignof(www_), alignof(www__));
printf("x: %2zu; x_: %2zu; x__: %2zu\n", alignof(struct x), alignof(x_), alignof(x__));
puts("xx: -");// printf("xx: %2zu; xx_: %2zu; xx__: %2zu\n", alignof(struct xx), alignof(xx_), alignof(xx__));
printf("xxx: %2zu; xxx_: %2zu; xxx__: %2zu\n\n", alignof(struct xxx), alignof(xxx_), alignof(xxx__));
printf("y: %2zu; y_: %2zu; y__: %2zu\n", alignof(struct y), alignof(y_), alignof(y__));
puts("yy: -");// printf("yy: %2zu; yy_: %2zu; yy__: %2zu\n", alignof(struct yy), alignof(yy_), alignof(yy__));
puts("yyy: -\n");// printf("yyy: %2zu; yyy_: %2zu; yyy__: %2zu\n\n", alignof(struct yyy), alignof(yyy_), alignof(yyy__));
printf("z: %2zu; z_: %2zu; z__: %2zu\n", alignof(struct z), alignof(z_), alignof(z__));
puts("zz: -");// printf("zz: %2zu; zz_: %2zu; zz__: %2zu\n", alignof(struct zz), alignof(zz_), alignof(zz__));
printf("zzz: %2zu; zzz_: %2zu; zzz__: %2zu\n", alignof(struct zzz), alignof(zzz_), alignof(zzz__));
return 0;
}cc -Wall -Wextra align.c -o align给出了我上面评论的警告和错误。我不得不注释掉一些代码以使其编译。
$ ./align
s: 8; s_: 8; s__: 8
t: 8; t_: 16; t__: 16
tt: 8; tt_: 16; tt__: 16
ttt: 8; ttt_: 16; ttt__: 16
u: 16; u_: 16; u__: 16
uu: -
uuu: 16; uuu_: 16; uuu__: 16
v: -
vv: -
vvv: -
w: 16; w_: 16; w__: 16
ww: 8; ww_: 16; ww__: 16
www: 8; www_: 16; www__: 16
x: 8; x_: 16; x__: 8
xx: -
xxx: 8; xxx_: 16; xxx__: 8
y: 8; y_: 8; y__: 16
yy: -
yyy: -
z: 8; z_: 8; z__: 16
zz: -
zzz: 8; zzz_: 8; zzz__: 16结论:
如果对齐属性位于struct关键字之前,它将应用于任何声明的变量,但不适用于类型本身。
如果属性介于struct关键字和struct标记之间,则它同时适用于声明的类型和任何变量。对于没有编译的C11 alignas(),这是无效的。
属性不能就在{之前。
如果属性位于}之后,则If的工作方式就好像在struct关键字之前一样(仅适用于声明的任何变量),但旧的GNU语法除外,后者也适用于类型本身。
如果该属性位于声明变量的后面,则它仅适用于它。对于没有编译的C11 alignas(),这是无效的。
如果属性位于一个声明的变量(不是第一个变量)之前( }和属性之间至少有一个逗号),那么它只适用于它旁边的变量。这只对旧的GNU语法有效;其他的则不编译。
https://stackoverflow.com/questions/67271825
复制相似问题