【发布时间】:2019-02-27 14:52:47
【问题描述】:
C11 标准第 6.2.5.20 节将数组定义为:
数组类型描述了一个连续分配的非空集合 具有特定成员对象类型的对象,称为元素类型。
虽然结构定义为:
结构类型描述了一个顺序分配的非空集合 成员对象(并且,在某些情况下,一个不完整的数组), 每个都有一个可选的指定名称并且可能不同 输入。
6.7.2.1 部分说可以在字段之间插入填充:
结构或联合对象的每个非位域成员都对齐 一种适合其类型的实现定义的方式。
在结构对象中,非位域成员和单元 哪些位域的地址按顺序增加 他们被宣布。指向结构对象的指针,适当地 转换后,指向其初始成员(或者如果该成员是 位域,然后到它所在的单元),反之亦然。 结构对象内可能有未命名的填充,但在其 开始。
但这是否意味着以下对象可能具有不同的内存布局?
struct A {
char x0;
short x1;
};
struct B {
struct A x0;
struct A x1;
struct A x2;
};
assert(sizeof(struct B) == sizeof(struct A[3]));
我创建了这个测试脚本来检查 GCC 的内存布局:
import itertools
import subprocess
src = """
#include "assert.h"
struct A {
{fields}
};
struct B {
struct A x0;
struct A x1;
struct A x2;
};
int main(int argc, char** argv) {
assert(sizeof(struct B) == sizeof(struct A[3]));
return 0;
}
"""
def main():
all_types = ["char", "short", "int", "long long"]
for types in itertools.product(all_types, repeat=3):
rendered = src.replace("{fields}", "".join([
" {} x{};\n".format(t, i)
for i, t in enumerate(types)]))
with open("main.c", "w") as f:
f.write(rendered)
subprocess.call(["gcc", "main.c"])
subprocess.call(["./a.out"])
if __name__ == "__main__":
main()
但 GCC 总是 为数组和结构生成相同的内存布局。
- 是否存在布局不同时的实际示例?
- 将此类结构实例转换为数组是否安全?
- 联合会更安全吗?
【问题讨论】:
-
禁用填充然后检查。
#pragma pack(push) #pragma pack(1) /* struct definition here */ #pragma pack(pop). -
@Lundin 试过了,但我得到了相同的结果——一切正常。
标签: c language-lawyer