C11(最新的免费草稿 http://www.open-std.org/jtc1/sc22/wg14/www/docs/n1570.pdf) 仅表示“结构对象内可能有未命名的填充,但不在其开头”(§6.7.2.1 ¶15) 和“结构或联合的末尾可能有未命名的填充”(§6.7.2.1 ¶ 17)。它对结构内的填充没有进一步的限制。
平台 ABI 可能对填充有更严格的要求,但这取决于平台特定,因为其他平台可能有其他填充要求。这适用于 Unix/Linux 的 x86-64 ABI http://www.x86-64.org/documentation/abi.pdf gives char
1 字节对齐,并指定:
结构和联合假定其最严格对齐的组件对齐。每个成员都被分配到具有适当的最低可用偏移量
结盟。任何对象的大小始终是对象对齐方式的倍数。
An array uses the same alignment as its elements, except that a local or global
array variable of length at least 16 bytes or a C99 variable-length array variable
always has alignment of at least 16 bytes4
结构和联合对象可能需要填充以满足大小和对齐的要求
限制。任何填充的内容都是未定义的。
4The alignment requirement allows the use of SSE instructions when operating on the array.
The compiler cannot in general calculate the size of a variable-length array (VLA), but it is ex-
pected that most VLAs will require at least 16 bytes, so it is logical to mandate that VLAs have at
least a 16-byte alignment.
这似乎意味着在这个平台上,结构内不会有填充。然而,在某些情况下,数组变量具有更严格的对齐限制,以便能够与向量指令一起使用;其他平台也可能对数组结构成员施加此类限制。
如果您想要可移植,在一次调用中读取结构时,您可能需要查看readv http://pubs.opengroup.org/onlinepubs/009695399/functions/readv.html。这是一个矢量或分散/聚集 I/O 操作 http://en.wikipedia.org/wiki/Vectored_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);
注意readv
是在 POSIX/Single Unix 规范中定义的,而不是在 C 标准中定义的。在标准 C 中,最简单的事情就是单独读取每个元素(即使有向量 I/O 可用,单独读取和写入每个元素可能会更清楚,除非您绝对需要对整个 I/O 操作)。
在您的编辑中,您写道:
接受的答案将根据 C 标准之一给出严格的或最严格的可移植实现,这让我可以使用标准库字符串函数处理这些字段。考虑到CHAR_BITS
和所有。我认为需要读取 512 的数组uint8_t
为此,之后可能会将它们一一转换为字符。有更简单的方法吗?
C 规范不保证uint8_t
可用:“typedef 名称uintN_t
指定宽度为 N 且无填充位的无符号整数类型......这些类型是可选的。”(C11 草案,§7.20.1.1,¶2–3)。但是,如果 8 位值可用,则char
保证是一个 8 位值,因为它保证至少是 8 位,并且保证是不是位字段的最小对象(§5.2.4.2.1 ¶1):
下面给出的值应替换为适合在中使用的常量表达式#if
预处理指令。而且,除了CHAR_BIT
and MB_LEN_MAX
,以下内容应替换为与根据整数提升转换的相应类型对象的表达式具有相同类型的表达式。它们的实现定义的值应等于或大于所示的值(绝对值),并具有相同的符号。
- — number of bits for smallest object that is not a bit-field (byte)
CHAR_BIT 8
因此,如果您没有可用的 8 位字节,您将无法直接读取这些字段并从中访问八位字节作为单独的数组元素;您必须使用位移位和掩码手动拆分各个字节。然而,据我所知,现代架构中没有缺少 8 位字节的(对于通用计算,文件 I/O 是一个问题;某些 DSP 可能会,但它们可能没有标准的 C 文件 I/O) )。
如果你确实有一个8位字节,那么char
保证为 8 位,因此除了使用起来清晰之外没有太多好处uint8_t
vs char
。如果你真的很担心,我只是确保你在构建过程中的某个地方进行了检查CHAR_BIT
是8并且称它为好。