C 标准中 char 数组结构成员的对齐

2024-05-05

假设我想读/写 tar 文件头。 考虑标准 C(C89、C99 或 C11), 关于填充,字符数组在结构中是否有任何特殊处理?编译器可以向这样的结构添加填充吗:

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];
};

我也在网络上的代码中看到过它的使用。只需读取该结构并将其写入一个块中的文件,假设不会有任何填充。当然也假设CHAR_BITS == 8。 我想这样的C代码很常见,标准会处理这种情况,但我就是找不到它,也许我不会成为一个好律师。

EDIT

接受的答案将根据 C 标准之一给出严格的或最严格的可移植实现,这让我可以使用标准库字符串函数处理这些字段。考虑到CHAR_BITS和所有。我认为需要读取 512 的数组uint8_t为此,之后可能会将它们一一转换为字符。有更简单的方法吗?


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 char1 字节对齐,并指定:

结构和联合假定其最严格对齐的组件对齐。每个成员都被分配到具有适当的最低可用偏移量 结盟。任何对象的大小始终是对象对齐方式的倍数。

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并且称它为好。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

C 标准中 char 数组结构成员的对齐 的相关文章

随机推荐