结构体
C语言中复杂的数据结构都需要使用结构体表示,在这里说一下结构体的使用要点。
结构体内存分布以及对齐问题
编译器在为结构体分配内存时,并不会分配和所有成员数据长度和恰好相等的内存空间,而是会考虑到计算机cpu的读取性能,对结构按照某个模数(alignment modulus)进行对齐。
例如结构体中拥有int (4个字节),char(1个字节)两个变量,但在使用sizeof进行大小输出时,并不是简单的各个成员数据的大小相加(4+1 = 5字节),而是经过编译器对齐后的8个字节
struct TestStruct {
int a;
char b;
}testStruct;
printf("%p \n",&testStruct); // 8
出现这样的结果,是因为编译器在对数据成员的内存地址上进行了对齐。而这种对齐是与计算机CPU相关的一种优化技术,计算机系统中对基本的数据类型在内存中的存放位置有限制,他们会要求这些数据的内存地址是某一个数的k倍,这个k值也被称为对齐模数(alignment modulus)
空结构体c与c++的sizeof得出的长度是不一致的
这是一个有意思的问题,对于无成员的结构体长度,c与c++的长度却是不一致的。空结构体的长度在c中为0,而c++中则为1。
struct NoPropertyStruct {
}noPropertyStruct;
printf("%lu \n",sizeof(noPropertyStruct)); // C时输出0,C++时输出1
查看C、C++两者的汇编代码
C`main:
0x100000f20 <+0>: pushq %rbp
0x100000f21 <+1>: movq %rsp, %rbp
0x100000f24 <+4>: subq $0x20, %rsp
0x100000f28 <+8>: leaq 0x62(%rip), %rax ; "sizeof(TestStruct) = %lu \n"
-> 0x100000f2f <+15>: xorl %ecx, %ecx ;对ecx做异或,也就是ecx置为0
0x100000f31 <+17>: movl %ecx, %edx
0x100000f33 <+19>: movl $0x0, -0x4(%rbp)
0x100000f3a <+26>: movl %edi, -0x8(%rbp)
0x100000f3d <+29>: movq %rsi, -0x10(%rbp)
0x100000f41 <+33>: movq %rax, %rdi
0x100000f44 <+36>: movq %rdx, %rsi
0x100000f47 <+39>: movb $0x0, %al
0x100000f49 <+41>: callq 0x100000f5e ; symbol stub for: printf
0x100000f4e <+46>: movl $0x1, %ecx
0x100000f53 <+51>: movl %eax, -0x14(%rbp)
0x100000f56 <+54>: movl %ecx, %eax
0x100000f58 <+56>: addq $0x20, %rsp
0x100000f5c <+60>: popq %rbp
0x100000f5d <+61>