空结构体和零长数组所占内存
今天突然看到一个有趣的东西,一个空的结构体占用内存空间是怎样的,就如下结构体:
struct test
{};
只定义一个结构体,结构体成员变量为NULL;那么sizeof(struct test) = ?,既然有定义,就应该要有内存分配,但是成员变量为空,那么就是分配内存。这就有了矛盾。到底是有内存还是没有。可以测试一下。
#include <stdio.h>
struct test
{
};
int main(int argc, char **argv)
{
printf("sizeof = %d\n", sizeof(struct test));
return 0;
}
编译执行结果:
结果为0,说明编译器还是没有分配内存的,换一种方式,直接定义一个结构体变量,改下代码:
#include <stdio.h>
struct test
{
};
int main(int argc, char **argv)
{
struct test test1;
printf("sizeof = %d\n", sizeof(test1));
return 0;
}
同样还是0,所以还是没有内存分配。
同样加上一个零长数组的话,测试一下:
#include <stdio.h>
struct test
{
};
int main(int argc, char **argv)
{
int a[0];
struct test test1;
printf("sizeof = %d\n", sizeof(test1));
printf("sizeof(a) = %d\n", sizeof(a));
return 0;
}
同样也是0,说明a[0]也是没有没分配内存的。
换成g++编译器试一下:
#include <iostream>
using namespace std;
struct test
{
};
int main(int argc, char **argv)
{
int a[0];
struct test test1;
cout << "sizeof(test1) = " << sizeof(test1) << endl;
cout << "sizeof(a) = " << sizeof(a) << endl;
return 0;
}
这里结构体是分配了最小的1字节,零长数组还是没有分配内存的。
所以这里针对结构体,看来针对不同编译器的处理还是有区别的。本想着反汇编看一下,结果汇编现在是一点都看不明白了。
linux-xv9p:~/lyx_test/字节对齐/sizeof_struct # objdump -S a.out
a.out: file format elf32-i386
Disassembly of section .init:
080482dc <_init>:
80482dc: 53 push %ebx
80482dd: 83 ec 08 sub $0x8,%esp
80482e0: e8 8b 00 00 00 call 8048370 <__x86.get_pc_thunk.bx>
80482e5: 81 c3 1b 1d 00 00 add $0x1d1b,%ebx
80482eb: 8b 83 fc ff ff ff mov -0x4(%ebx),%eax
80482f1: 85 c0 test %eax,%eax
80482f3: 74 05 je 80482fa <_init+0x1e>
80482f5: e8 26 00 00 00 call 8048320 <__gmon_start__@plt>
80482fa: 83 c4 08 add $0x8,%esp
80482fd: 5b pop %ebx
80482fe: c3 ret
Disassembly of section .plt:
08048300 <printf@plt-0x10>:
8048300: ff 35 04 a0 04 08 pushl 0x804a004
8048306: ff 25 08 a0 04 08 jmp *0x804a008
804830c: 00 00 add %al,(%eax)
...
08048310 <printf@plt>:
8048310: ff 25 0c a0 04 08 jmp *0x804a00c
8048316: 68 00 00 00 00 push $0x0
804831b: e9 e0 ff ff ff jmp 8048300 <_init+0x24>
08048320 <__gmon_start__@plt>:
8048320: ff 25 10 a0 04 08 jmp *0x804a010
8048326: 68 08 00 00 00 push $0x8
804832b: e9 d0 ff ff ff jmp 8048300 <_init+0x24>
08048330 <__libc_start_main@plt>:
8048330: ff 25 14 a0 04 08 jmp *0x804a014
8048336: 68 10 00 00 00 push $0x10
804833b: e9 c0 ff ff ff jmp 8048300 <_init+0x24>
Disassembly of section .text:
08048340 <_start>:
8048340: 31 ed xor %ebp,%ebp
8048342: 5e pop %esi
8048343: 89 e1 mov %esp,%ecx
8048345: 83 e4 f0 and $0xfffffff0,%esp
8048348: 50 push %eax
8048349: 54 push %esp
804834a: 52 push %edx
804834b: 68 f0 84 04 08 push $0x80484f0
8048350: 68 80 84 04 08 push $0x8048480
8048355: 51 push %ecx
8048356: 56 push %esi
8048357: 68 40 84 04 08 push $0x8048440
804835c: e8 cf ff ff ff call 8048330 <__libc_start_main@plt>
8048361: f4 hlt
8048362: 66 90 xchg %ax,%ax
8048364: 66 90 xchg %ax,%ax
8048366: 66 90 xchg %ax,%ax
8048368: 66 90 xchg %ax,%ax
804836a: 66 90 xchg %ax,%ax
804836c: 66 90 xchg %ax,%ax
804836e: 66 90 xchg %ax,%ax
08048370 <__x86.get_pc_thunk.bx>:
8048370: 8b 1c 24 mov (%esp),%ebx
8048373: c3 ret
8048374: 66 90 xchg %ax,%ax
8048376: 66 90 xchg %ax,%ax
8048378: 66 90 xchg %ax,%ax
804837a: 66 90 xchg %ax,%ax
804837c: 66 90 xchg %ax,%ax
804837e: 66 90 xchg %ax,%ax
08048380 <deregister_tm_clones>:
8048380: b8 23 a0 04 08 mov $0x804a023,%eax
8048385: 2d 20 a0 04 08 sub $0x804a020,%eax
804838a: 83 f8 06 cmp $0x6,%eax
804838d: 77 01 ja 8048390 <deregister_tm_clones+0x10>
804838f: c3 ret
8048390: b8 00 00 00 00 mov $0x0,%eax
8048395: 85 c0 test %eax,%eax
8048397: 74 f6 je 804838f <deregister_tm_clones+0xf>
8048399: 55 push %ebp
804839a: 89 e5 mov %esp,%ebp
804839c: 83 ec 18 sub $0x18,%esp
804839f: c7 04 24 20 a0 04 08 movl $0x804a020,(%esp)
80483a6: ff d0 call *%eax
80483a8: c9 leave
80483a9: c3 ret
80483aa: 8d b6 00 00 00 00 lea 0x0(%esi),%esi
080483b0 <register_tm_clones>:
80483b0: b8 20 a0 04 08 mov $0x804a020,%eax
80483b5: 2d 20 a0 04 08 sub $0x804a020,%eax
80483ba: c1 f8 02 sar $0x2,%eax
80483bd: 89 c2 mov %eax,%edx
80483bf: c1 ea 1f shr $0x1f,%edx
80483c2: 01 d0 add %edx,%eax
80483c4: d1 f8 sar %eax
80483c6: 75 01 jne 80483c9 <register_tm_clones+0x19>
80483c8: c3 ret
80483c9: ba 00 00 00 00 mov $0x0,%edx
80483ce: 85 d2 test %edx,%edx
80483d0: 74 f6 je 80483c8 <register_tm_clones+0x18>
80483d2: 55 push %ebp
80483d3: 89 e5 mov %esp,%ebp
80483d5: 83 ec 18 sub $0x18,%esp
80483d8: 89 44 24 04 mov %eax,0x4(%esp)
80483dc: c7 04 24 20 a0 04 08 movl $0x804a020,(%esp)
80483e3: ff d2 call *%edx
80483e5: c9 leave
80483e6: c3 ret
80483e7: 89 f6 mov %esi,%esi
80483e9: 8d bc 27 00 00 00 00 lea 0x0(%edi,%eiz,1),%edi
080483f0 <__do_global_dtors_aux>:
80483f0: 80 3d 20 a0 04 08 00 cmpb $0x0,0x804a020
80483f7: 75 13 jne 804840c <__do_global_dtors_aux+0x1c>
80483f9: 55 push %ebp
80483fa: 89 e5 mov %esp,%ebp
80483fc: 83 ec 08 sub $0x8,%esp
80483ff: e8 7c ff ff ff call 8048380 <deregister_tm_clones>
8048404: c6 05 20 a0 04 08 01 movb $0x1,0x804a020
804840b: c9 leave
804840c: f3 c3 repz ret
804840e: 66 90 xchg %ax,%ax
08048410 <frame_dummy>:
8048410: a1 08 9f 04 08 mov 0x8049f08,%eax
8048415: 85 c0 test %eax,%eax
8048417: 74 1f je 8048438 <frame_dummy+0x28>
8048419: b8 00 00 00 00 mov $0x0,%eax
804841e: 85 c0 test %eax,%eax
8048420: 74 16 je 8048438 <frame_dummy+0x28>
8048422: 55 push %ebp
8048423: 89 e5 mov %esp,%ebp
8048425: 83 ec 18 sub $0x18,%esp
8048428: c7 04 24 08 9f 04 08 movl $0x8049f08,(%esp)
804842f: ff d0 call *%eax
8048431: c9 leave
8048432: e9 79 ff ff ff jmp 80483b0 <register_tm_clones>
8048437: 90 nop
8048438: e9 73 ff ff ff jmp 80483b0 <register_tm_clones>
804843d: 66 90 xchg %ax,%ax
804843f: 90 nop
08048440 <main>:
8048440: 55 push %ebp
8048441: 89 e5 mov %esp,%ebp
8048443: 83 e4 f0 and $0xfffffff0,%esp
8048446: 83 ec 10 sub $0x10,%esp
8048449: c7 44 24 04 00 00 00 movl $0x0,0x4(%esp)
8048450: 00
8048451: c7 04 24 10 85 04 08 movl $0x8048510,(%esp)
8048458: e8 b3 fe ff ff call 8048310 <printf@plt>
804845d: c7 44 24 04 00 00 00 movl $0x0,0x4(%esp)
8048464: 00
8048465: c7 04 24 1d 85 04 08 movl $0x804851d,(%esp)
804846c: e8 9f fe ff ff call 8048310 <printf@plt>
8048471: b8 00 00 00 00 mov $0x0,%eax
8048476: c9 leave
8048477: c3 ret
8048478: 66 90 xchg %ax,%ax
804847a: 66 90 xchg %ax,%ax
804847c: 66 90 xchg %ax,%ax
804847e: 66 90 xchg %ax,%ax
08048480 <__libc_csu_init>:
8048480: 55 push %ebp
8048481: 57 push %edi
8048482: 31 ff xor %edi,%edi
8048484: 56 push %esi
8048485: 53 push %ebx
8048486: e8 e5 fe ff ff call 8048370 <__x86.get_pc_thunk.bx>
804848b: 81 c3 75 1b 00 00 add $0x1b75,%ebx
8048491: 83 ec 1c sub $0x1c,%esp
8048494: 8b 6c 24 30 mov 0x30(%esp),%ebp
8048498: 8d b3 04 ff ff ff lea -0xfc(%ebx),%esi
804849e: e8 39 fe ff ff call 80482dc <_init>
80484a3: 8d 83 00 ff ff ff lea -0x100(%ebx),%eax
80484a9: 29 c6 sub %eax,%esi
80484ab: c1 fe 02 sar $0x2,%esi
80484ae: 85 f6 test %esi,%esi
80484b0: 74 27 je 80484d9 <__libc_csu_init+0x59>
80484b2: 8d b6 00 00 00 00 lea 0x0(%esi),%esi
80484b8: 8b 44 24 38 mov 0x38(%esp),%eax
80484bc: 89 2c 24 mov %ebp,(%esp)
80484bf: 89 44 24 08 mov %eax,0x8(%esp)
80484c3: 8b 44 24 34 mov 0x34(%esp),%eax
80484c7: 89 44 24 04 mov %eax,0x4(%esp)
80484cb: ff 94 bb 00 ff ff ff call *-0x100(%ebx,%edi,4)
80484d2: 83 c7 01 add $0x1,%edi
80484d5: 39 f7 cmp %esi,%edi
80484d7: 75 df jne 80484b8 <__libc_csu_init+0x38>
80484d9: 83 c4 1c add $0x1c,%esp
80484dc: 5b pop %ebx
80484dd: 5e pop %esi
80484de: 5f pop %edi
80484df: 5d pop %ebp
80484e0: c3 ret
80484e1: eb 0d jmp 80484f0 <__libc_csu_fini>
80484e3: 90 nop
80484e4: 90 nop
80484e5: 90 nop
80484e6: 90 nop
80484e7: 90 nop
80484e8: 90 nop
80484e9: 90 nop
80484ea: 90 nop
80484eb: 90 nop
80484ec: 90 nop
80484ed: 90 nop
80484ee: 90 nop
80484ef: 90 nop
080484f0 <__libc_csu_fini>:
80484f0: f3 c3 repz ret
80484f2: 66 90 xchg %ax,%ax
Disassembly of section .fini:
080484f4 <_fini>:
80484f4: 53 push %ebx
80484f5: 83 ec 08 sub $0x8,%esp
80484f8: e8 73 fe ff ff call 8048370 <__x86.get_pc_thunk.bx>
80484fd: 81 c3 03 1b 00 00 add $0x1b03,%ebx
8048503: 83 c4 08 add $0x8,%esp
8048506: 5b pop %ebx
8048507: c3 ret
linux-xv9p:~/lyx_test/字节对齐/sizeof_struct #
这是针对c语言那份二进制文件进行的反汇编。等我回头看看汇编以及找时间看看编译原理再来说这个问题吧。这看起来就是和编译器有关系了,这个问题大家知道就好了,实际工作中应该不会去使用这种东西,除非某种特殊场景需要特殊处理,其他的应该不会出现这种情况,反正我是没遇到过。