在 GNU GCC 中使用 __attribute__((__packed__)) 结构打包
Structure Packing using __attribute__((__packed__)) in GNU GCC
我们知道 _attribute__((__packed__))
表示(很可能) "do not insert any padding to make things faster" 也可能表示 "do not insert any alignments to preserve alignment".
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)?
尝试:
struct __attribute__((__packed__)) structure2
{ // ^^^^^^^^^^^^^^^^^^^^^^^^^^^
int id1;
char name;
int id2;
char c;
float percentage;
};
打包一个字段没有意义。正如您自己所说,填充是关于字段之间的关系,因此该属性属于结构本身,而不属于其字段。
在我看来像是一个错误...
通过使用您的编译器 ((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 [=10=]x40,%rsp
401508: e8 a3 11 00 00 callq 4026b0 <__main>
40150d: ba 14 00 00 00 mov [=10=]x14,%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 [=10=]x0,%eax
401523: 48 83 c4 40 add [=10=]x40,%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 [=11=]x30,%rsp
1004010e8: e8 33 00 00 00 callq 100401120 <__main>
1004010ed: ba 0e 00 00 00 mov [=11=]xe,%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 [=11=]x0,%eax
100401103: 48 83 c4 30 add [=11=]x30,%rsp
100401107: 5d pop %rbp
100401108: c3 retq
...
因此,出于某种原因,您使用的编译器似乎忽略了该属性。不过,您可能想尝试更新的版本 - 这个 TDM-GCC
的最新版本似乎是 5.1.0。
我们知道 _attribute__((__packed__))
表示(很可能) "do not insert any padding to make things faster" 也可能表示 "do not insert any alignments to preserve alignment".
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)?
尝试:
struct __attribute__((__packed__)) structure2
{ // ^^^^^^^^^^^^^^^^^^^^^^^^^^^
int id1;
char name;
int id2;
char c;
float percentage;
};
打包一个字段没有意义。正如您自己所说,填充是关于字段之间的关系,因此该属性属于结构本身,而不属于其字段。
在我看来像是一个错误...
通过使用您的编译器 ((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 [=10=]x40,%rsp
401508: e8 a3 11 00 00 callq 4026b0 <__main>
40150d: ba 14 00 00 00 mov [=10=]x14,%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 [=10=]x0,%eax
401523: 48 83 c4 40 add [=10=]x40,%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 [=11=]x30,%rsp
1004010e8: e8 33 00 00 00 callq 100401120 <__main>
1004010ed: ba 0e 00 00 00 mov [=11=]xe,%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 [=11=]x0,%eax
100401103: 48 83 c4 30 add [=11=]x30,%rsp
100401107: 5d pop %rbp
100401108: c3 retq
...
因此,出于某种原因,您使用的编译器似乎忽略了该属性。不过,您可能想尝试更新的版本 - 这个 TDM-GCC
的最新版本似乎是 5.1.0。