在GNU GCC中使用`__attribute__((__packed__))`进行结构体打包

4

我们知道_attribute__((__packed__))的意思(很可能)是“不插入任何填充以加快速度”,也可能是“不插入任何对齐以保持对齐”。

struct structure2
{
   int id1 __attribute__((__packed__));
   char name __attribute__((__packed__));
   int id2 __attribute__((__packed__));
   char c __attribute__((__packed__));
   float percentage __attribute__((__packed__));
};
struct structure2 b;
printf("   \n\nsize of structure2 in bytes : %d\n", sizeof(b));// output = 20

为什么所有的填充都没有被移除(输出结果为14)?

在使用供应商扩展之前,请务必阅读文档。文档明确指出该属性只能附加到结构体、联合体和枚举类型。 - Kerrek SB
您希望struct被打包,而不是单个字段(因为它们已经作为标量类型打包)。 - too honest for this site
我从http://grok2.tripod.com/structure_packing.html看到了这种类型的结构。 - Animesh Kumar Paul
2个回答

13

尝试:

struct __attribute__((__packed__)) structure2
{  //  ^^^^^^^^^^^^^^^^^^^^^^^^^^^
   int id1;
   char name;
   int id2;
   char c;
   float percentage;
};

将单个字段打包是没有意义的。正如您自己所说,填充是关于字段之间的关系,因此属性应该属于结构体本身,而不是它的字段。


1
@AnimeshKumarPaul:无法复现,我这里可以运行 - Kerrek SB
@AnimeshKumarPaul 你使用的gcc版本是多少? - dragosht
@dragosht,gcc版本为4.7.1(tdm-1)。 - Animesh Kumar Paul
3
__attribute__((packed))可以放置在结构体的最后一个 }; 之间,如下所示:struct structure2 { ... } __attribute__((packed)) ; - Clifford
@AnimeshKumarPaul:在Wandbox上检查,即使在GCC 4.7.3上,这也能按预期工作。 - Kerrek SB
显示剩余2条评论

2

看起来对我来说是个Bug ...

使用你的编译器 ((tdm64-1) 4.7.1) 和适当的 packed 属性,我得到了相同的行为 - 参见下面的 main 反汇编:

0000000000401500 <main>:
  401500:       55                      push   %rbp
  401501:       48 89 e5                mov    %rsp,%rbp
  401504:       48 83 ec 40             sub    $0x40,%rsp
  401508:       e8 a3 11 00 00          callq  4026b0 <__main>
  40150d:       ba 14 00 00 00          mov    $0x14,%edx <-- your sizeof here
  401512:       48 8d 0d 07 7b 00 00    lea    0x7b07(%rip),%rcx        # 409020 <.rdata>
  401519:       e8 b2 60 00 00          callq  4075d0 <printf>
  40151e:       b8 00 00 00 00          mov    $0x0,%eax
  401523:       48 83 c4 40             add    $0x40,%rsp
  401527:       5d                      pop    %rbp
  401528:       c3                      retq
  ...

在cygwin中使用gcc (GCC) 4.9.3,我得到以下结果:
00000001004010e0 <main>:
   1004010e0:   55                      push   %rbp
   1004010e1:   48 89 e5                mov    %rsp,%rbp
   1004010e4:   48 83 ec 30             sub    $0x30,%rsp
   1004010e8:   e8 33 00 00 00          callq  100401120 <__main>
   1004010ed:   ba 0e 00 00 00          mov    $0xe,%edx <-- your sizeof here
   1004010f2:   48 8d 0d 37 1f 00 00    lea    0x1f37(%rip),%rcx        # 100403030 <.rdata>
   1004010f9:   e8 32 00 00 00          callq  100401130 <printf>
   1004010fe:   b8 00 00 00 00          mov    $0x0,%eax
   100401103:   48 83 c4 30             add    $0x30,%rsp
   100401107:   5d                      pop    %rbp
   100401108:   c3                      retq
   ...

所以,由于某种原因,你正在使用的编译器似乎忽略了该属性。你可以尝试使用更新的版本,最新版本的TDM-GCC似乎是5.1.0。


有问题的编译器是否也支持OP的每个字段语法?最近的GCC不支持(它不允许在char字段上使用属性)。 - Kerrek SB
1
是的,我刚刚看到原帖作者从外部文档复制了代码,所以我想知道它是否曾经被GCC支持过。不过没关系。 - Kerrek SB

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接