c-__attribute__((packed))和声明中的[[gnu::packed]]位置



packed属性应放在声明中的何处?C2x(C++风格(和旧GNU属性的使用有什么区别吗?

鉴于GCC文档不是很清楚,我开发了以下测试程序作为实验答案:

#include <stdio.h>
struct s {
char a;
long b;
char c;
} s_, s__;
// warning: 'packed' attribute ignored [-Wattributes]
__attribute__((packed)) struct t {
char a;
long b;
char c;
} t_, t__;
// warning: 'packed' attribute ignored [-Wattributes]
[[gnu::packed]] struct ttt {
char a;
long b;
char c;
} ttt_, ttt__;
struct __attribute__((packed)) u {
char a;
long b;
char c;
} u_, u__;
struct [[gnu::packed]] uuu {
char a;
long b;
char c;
} uuu_, uuu__;
// error: expected identifier or '(' before '{' token
/*
struct v __attribute__((packed)) {
char a;
long b;
char c;
} v_, v_;
*/
// error: expected identifier or '(' before '{' token
/*
struct vvv [[gnu::packed]] {
char a;
long b;
char c;
} vvv_, vvv__;
*/
struct w {
char a;
long b;
char c;
} __attribute__((packed)) w_, w__;
// warning: 'packed' attribute ignored for type 'struct www' [-Wattributes]
struct www {
char a;
long b;
char c;
} [[gnu::packed]] www_, www__;
// warning: 'packed' attribute ignored [-Wattributes]
struct x {
char a;
long b;
char c;
} x_ __attribute__((packed)), x__;
// warning: 'packed' attribute ignored [-Wattributes]
struct xxx {
char a;
long b;
char c;
} xxx_ [[gnu::packed]], xxx__;
// warning: 'packed' attribute ignored [-Wattributes]
struct y {
char a;
long b;
char c;
} y_, __attribute__((packed)) y__;
// error: expected identifier or '(' before '[' token
/*
struct yyy {
char a;
long b;
char c;
} yyy_, [[gnu::packed]] yyy__;
*/
// warning: 'packed' attribute ignored [-Wattributes]
struct z {
char a;
long b;
char c;
} z_, z__ __attribute__((packed));
// warning: 'packed' attribute ignored [-Wattributes]
struct zzz {
char a;
long b;
char c;
} zzz_, zzz__ [[gnu::packed]];

int main(void)
{
printf("s:   %2zu;  s_:   %2zu; s__:     %2zunn", sizeof(struct s), sizeof(s_), sizeof(s__));
printf("t:   %2zu;  t_:   %2zu; t__:     %2zun", sizeof(struct t), sizeof(t_), sizeof(t__));
printf("ttt: %2zu;  ttt_: %2zu; ttt__:   %2zunn", sizeof(struct ttt), sizeof(ttt_), sizeof(ttt__));
printf("u:   %2zu;  u_:   %2zu; u__:     %2zun", sizeof(struct u), sizeof(u_), sizeof(u__));
printf("uuu: %2zu;  uuu_: %2zu; uuu__:   %2zunn", sizeof(struct uuu), sizeof(uuu_), sizeof(uuu__));
puts("v:   -");//  printf("v:   %2zu;  v_:   %2zu; v__:     %2zun", sizeof(struct v), sizeof(v_), sizeof(v__));
puts("vvv: -n");//  printf("vvv: %2zu;  vvv_: %2zu; vvv__:   %2zun", sizeof(struct vvv), sizeof(vvv_), sizeof(vvv__));
printf("w:   %2zu;  w_:   %2zu; w__:     %2zun", sizeof(struct w), sizeof(w_), sizeof(w__));
printf("www: %2zu;  www_: %2zu; www__:   %2zunn", sizeof(struct www), sizeof(www_), sizeof(www__));
printf("x:   %2zu;  x_:   %2zu; x__:     %2zun", sizeof(struct x), sizeof(x_), sizeof(x__));
printf("xxx: %2zu;  xxx_: %2zu; xxx__:   %2zunn", sizeof(struct xxx), sizeof(xxx_), sizeof(xxx__));
printf("y:   %2zu;  y_:   %2zu; y__:     %2zun", sizeof(struct y), sizeof(y_), sizeof(y__));
puts("yyy: -n");//  printf("yyy: %2zu;  yyy_: %2zu; yyy__:   %2zunn", sizeof(struct yyy), sizeof(yyy_), sizeof(yyy__));
printf("z:   %2zu;  z_:   %2zu; z__:     %2zun", sizeof(struct z), sizeof(z_), sizeof(z__));
printf("zzz: %2zu;  zzz_: %2zu; zzz__:   %2zun", sizeof(struct zzz), sizeof(zzz_), sizeof(zzz__));
return 0;
}

cc -Wall -Wextra -o packed packed.c给出了我在上面评论的警告和错误。我不得不注释掉一些代码以使其编译。

$ ./packed 
s:   24;  s_:   24; s__:     24
t:   24;  t_:   24; t__:     24
ttt: 24;  ttt_: 24; ttt__:   24
u:   10;  u_:   10; u__:     10
uuu: 10;  uuu_: 10; uuu__:   10
v:   -
vvv: -
w:   10;  w_:   10; w__:     10
www: 24;  www_: 24; www__:   24
x:   24;  x_:   24; x__:     24
xxx: 24;  xxx_: 24; xxx__:   24
y:   24;  y_:   24; y__:     24
yyy: -
z:   24;  z_:   24; z__:     24
zzz: 24;  zzz_: 24; zzz__:   24

结论:

与对齐属性不同,它只适用于类型,而不适用于变量。变量被压缩iff[1]其类型被压缩。这是有道理的;否则,无法将一个变量分配给同一类型的另一个变量。

C2x(C++样式(属性只能位于struct关键字和struct标记之间。

旧的GNU样式属性可以放在C2x的位置,也可以放在右大括号之后。


[1]:

$ wtf is iff
IFF: if and only if

最新更新