#include <iostream>
using namespace std;
struct node1{
char b[3];
int c[0];
};
struct node2{
int c[0];
};
struct node3{
char b[3];
};
int main() {
cout << sizeof(node1) << endl; // prints 4
cout << sizeof(node2) << endl; // prints 0
cout << sizeof(node3) << endl; // prints 3
}
我的问题是为什么编译器为node2中的int c [0]分配0个字节 但在node1的一部分时为其分配1个字节。 我假设这个1字节是sizeof(node1)返回4的原因,因为没有它(比如在node3中)它的大小是3或者是由于填充?
还试图了解node2是否应该有足够的空间来保存指向数组的指针(作为灵活数组/结构黑客攻击的一部分,它将在代码中进一步分配?
答案 0 :(得分:2)
是的,它是关于填充/对齐的。如果您将__attribute__((__packed__))
添加到最后[在编写设备驱动程序时很有用],那么您的输出将获得3 0 3
。
如果node1定义了c [1],则大小为8而不是7,因为编译器会将c与int边界对齐。随着打包,sizeof将是7
答案 1 :(得分:2)
是的,填充有所不同。 node1
具有填充字节而node3
没有填充字节的原因在于零长度数组的典型用法。
零长度数组通常与强制转换一起使用:将较大的(可能是可变大小的)对象强制转换为包含零长度数组的结构。然后使用零长度数组访问大对象的“其余”,为此,必须正确对齐。在零大小的数组之前插入填充字节,以使int
对齐。由于您无法使用node3
执行此操作,因此无需填充。
示例:
struct Message {
char Type[3];
int Data[]; // it compiles without putting 0 explicitly
};
void ReceiveMessage(unsigned char* buffer, size_t length) {
if(length < sizeof(Message))
return;
Message* msg = (Message*)buffer;
if(!memcmp(msg->Type, "GET", 3)) {
HandleGet(msg->Data, (length - sizeof(Message))/sizeof(int));
} else if....
注意:这是相当hackish,但效率很高。
答案 2 :(得分:0)
c
并未在node1
中分配一个字节。这是因为填充添加到b
。
对于b
,可以通过32位CPU轻松获得,它大四个字节。 32位CPU一次可以从内存中读取4个连续字节。要阅读三篇,他们必须阅读四篇,然后删除一篇不必要的内容。因此,为了优化此行为,编译器将struct
填充一些字节。
当在栈上推送值时(即分配了参数或局部变量),您可以观察到类似的编译器优化。堆栈始终与CPU的数据总线大小保持一致(通常为32或64位)。
答案 3 :(得分:0)
int main() {
cout << sizeof(node1) << endl; // prints 4
cout << sizeof(node2) << endl; // prints 0
cout << sizeof(node3) << endl; // prints 3
}
main函数查询用户定义的结构的大小,而不是数组成员的大小。 sizeof()将返回分配给结构的字节数,字符数组中分配的每个字符分配1个字节。字符数组实际上是一个C风格的字符串,由标记字符'\ 0'终止。在评估sizeof(node1)时,可能包括分配用于保存sentinel字符的字节,因为它之后有另一个变量,因此它会读取它,但不包括sizeof(node3)中的sentinel,其中字符串和struct终止