在C语言中,联合体(union)有点像结构体那样,把不同类型的数据组织起来,但和结构体不大一样,在结构体各成员有各自的内存空间,一个结构体对象的总长度是各成员长度之和。而在联合体中,各成员共享一段内存空间,一个联合体对象的长度等于各成员中最长的长度。
由上面描述可知,联合体应该具备多面性,即在汇编层面上,有时候会显示结构体的特征,或数组特征,或其它基本数据类型特征。
先看一下例子:
1 #include <stdio.h> 2 union xuzhina_dump_c05_s4 3 { 4 int i; 5 char hello[4]; 6 }; 7 8 int main() 9 { 10 union xuzhina_dump_c05_s4 test; 11 test.i = 0x656463; 12 for ( int i = 0; i < 4; i++ ) 13 { 14 printf( "%c", test.hello[i] ); 15 } 16 17 printf( "\n" ); 18 return 0; 19 }
(gdb) disassemble main Dump of assembler code for function main: 0x08048570 <+0>: push %ebp 0x08048571 <+1>: mov %esp,%ebp 0x08048573 <+3>: and $0xfffffff0,%esp 0x08048576 <+6>: sub $0x20,%esp 0x08048579 <+9>: movl $0x656463,0x18(%esp) 0x08048581 <+17>: movl $0x0,0x1c(%esp) 0x08048589 <+25>: jmp 0x80485a8 <main+56> 0x0804858b <+27>: lea 0x18(%esp),%edx 0x0804858f <+31>: mov 0x1c(%esp),%eax 0x08048593 <+35>: add %edx,%eax 0x08048595 <+37>: movzbl (%eax),%eax 0x08048598 <+40>: movsbl %al,%eax 0x0804859b <+43>: mov %eax,(%esp) 0x0804859e <+46>: call 0x8048430 <putchar@plt> 0x080485a3 <+51>: addl $0x1,0x1c(%esp) 0x080485a8 <+56>: cmpl $0x3,0x1c(%esp) 0x080485ad <+61>: setle %al 0x080485b0 <+64>: test %al,%al 0x080485b2 <+66>: jne 0x804858b <main+27> 0x080485b4 <+68>: movl $0xa,(%esp) 0x080485bb <+75>: call 0x8048430 <putchar@plt> 0x080485c0 <+80>: mov $0x0,%eax 0x080485c5 <+85>: jmp 0x80485cf <main+95> 0x080485c7 <+87>: mov %eax,(%esp) 0x080485ca <+90>: call 0x8048460 <_Unwind_Resume@plt> 0x080485cf <+95>: leave 0x080485d0 <+96>: ret End of assembler dump.
从上面汇编代码来看,unionxuzhina_dump_c05_s4确实以int和char数组进行访问。见下面这两组指令
0x08048579 <+9>: movl $0x656463,0x18(%esp) 0x0804858b <+27>: lea 0x18(%esp),%edx 0x0804858f <+31>: mov 0x1c(%esp),%eax 0x08048593 <+35>: add %edx,%eax 0x08048595 <+37>: movzbl (%eax),%eax
由上面的探讨,union成员类型最好避免是指针类型。因为指针容易被覆盖,会发生“Accessviolation”的错误。假设指针是函数指针,则会出现上一节的coredump。
《coredump问题原理探究》Linux x86版5.8节C风格数据结构内存布局之联合体
原文地址:http://blog.csdn.net/xuzhina/article/details/41383213