Gáb*_*lla 3 c standards struct alignment
让我们假设我想读/写一个tar文件头.考虑到标准C(C89,C99或C11),char数组在结构上是否有任何特殊处理,关于填充?编译器可以为这样的结构添加填充:
struct header {
char name[100];
char mode[8];
char uid[8];
char gid[8];
char size[12];
char mtime[12];
char chksum[8];
char typeflag;
char linkname[100];
char tail[255];
};
Run Code Online (Sandbox Code Playgroud)
我已经看到它也用在网络上的代码中.只是自由,将这个结构写入一个块中的文件,假设不会有任何填充.当然也有假设CHAR_BITS == 8.我认为这样的C代码是如此常见,标准会处理这种情况,但我只是找不到它,也许我不会是一个好律师.
编辑
接受的答案将根据C标准之一给出严格或最严格的可移植实现,这使我可以使用标准库字符串函数处理这些字段.考虑CHAR_BITS到所有.我认为需要为此读取512的数组uint8_t,然后可能将它们逐个转换为字符.有更简单的方法吗
C11(最新的免费草案)仅说"结构对象中可能有未命名的填充,但不是在其开头"(§6.7.2.115)和"结构或联合的末尾可能有未命名的填充" "(§6.7.2.117).它对结构内的填充没有进一步的限制.
平台ABI可能对填充有更严格的要求,但取决于此将是平台特定的,因为其他平台可能具有其他填充要求.Unix/Linux的x86-64 ABI提供char1字节对齐,并指定:
结构和联合体假定其最严格对齐的组件对齐.每个成员都被分配到具有适当对齐的最低可用偏移量.任何对象的大小始终是对象对齐的倍数.
数组使用与其元素相同的对齐方式,除了长度至少为16个字节的本地或全局数组变量或C99可变长度数组变量始终具有至少16个字节的对齐方式4
结构和联合对象可能需要填充以满足大小和对齐约束.任何填充的内容都是未定义的.
4对齐要求允许在阵列上操作时使用SSE指令.编译器通常不能计算可变长度数组(VLA)的大小,但预计大多数VLA需要至少16个字节,因此要求VLA至少具有16个字节的对齐是合乎逻辑的. .
这似乎意味着在这个平台上,结构中不会有填充.但是,有些情况下,数组变量具有更严格的对齐限制,以便能够与向量指令一起使用; 其他平台也可能对阵列结构成员施加此类限制.
如果您想要便携,在一次通话中阅读结构时,您可能需要查看readv.这是一个向量或分散/聚集I/O操作,它允许您指定要读入的数组和长度数组.例如,对于这种情况,您可以写:
struct header h;
struct iovec iov[10];
iov[0].iov_base = &h.name;
iov[0].iov_len = sizeof(h.name);
iov[1].iov_base = &h.mode;
iov[1].iov_len = sizeof(h.mode);
/* ... etc ... */
bytes_read = readv(fd, iov, 10);
Run Code Online (Sandbox Code Playgroud)
注意,它readv是在POSIX/Single Unix规范中定义的,而不是在C标准中定义的.在标准C中,最简单的方法就是单独读取每个元素(即使有向量I/O可用,只需单独读取和写入每个元素可能会更加清晰,除非您绝对需要使用单个调用整个I/O操作).
在您的编辑中,您写道:
接受的答案将根据C标准之一给出严格或最严格的可移植实现,这使我可以使用标准库字符串函数处理这些字段.考虑
CHAR_BITS到所有.我认为需要为此读取512的数组uint8_t,然后可能将它们逐个转换为字符.有更简单的方法吗
C规范不保证uint8_t可用:"typedef名称指定一个宽度为N且没有填充位的无符号整数类型....这些类型是可选的." (C11草案,§7.20.1.1,2-3).但是,如果8位值可用,则保证为8位值,因为它保证至少为8位,并且保证是不是位字段的最小对象(§5.2.4.2. 11):uintN_tchar
下面给出的值应替换为适用于
#if预处理指令的常量表达式.此外,除了CHAR_BIT和之外MB_LEN_MAX,以下内容应由与表达式相同的表达式替换,该表达式是根据整数提升转换的相应类型的对象.它们的实现定义值的大小(绝对值)应等于或大于显示的值,并带有相同的符号.
- - 不是位字段(字节)的最小对象的位数
CHAR_BIT 8
因此,如果您没有可用的8位字节,您将无法直接读取这些字段并从它们作为单独的数组元素访问八位字节; 您必须使用位移和屏蔽手动拆分单个字节.但是,我所知道的现代架构缺少8位字节(对于通用计算,文件I/O完全是一个问题;某些DSP可能,但它们可能没有标准的C文件I/O ).
如果你有一个8位字节,那么char保证是8位,所以除了使用uint8_tvs的清晰度之外没有太多的好处char.如果您真的担心,我会确保您在构建过程中的某个位置检查CHAR_BIT是8并将其称为好.