【发布时间】:2014-11-23 19:28:20
【问题描述】:
很明显,C 中的数组cannot insert padding between their elements。但是,是否有任何规则说他们不能在整个数组的 end 处添加尾随填充?
即这个程序是否保证在任何地方都能给出相同的结果?
#include <stdio.h>
int main(void) {
typedef char a[3];
typedef a b[3];
printf("%zu %zu\n", sizeof(a), sizeof(b)); // -> 3 9
}
据我所知,在a 的大小上添加一个或五个尾随字节,也许是在错误的优化尝试中,不会破坏数组访问规则(b[1][1] 仍然精确映射到 @987654325 @ 不管其包含的a 对象的大小如何,并且访问超出包含的a 的长度无论如何都是UB)。
我在 C 标准中找不到任何地方 说 数组的大小是元素类型的大小乘以元素的数量。 6.5.3.4 只说 sizeof 返回数组中的“字节数”(它确实给出了 sizeof array / sizeof array[0] 作为代码示例,但这只是一个示例 - 它并没有说它必须工作,它没有提供任何细节)。
隐式保证对于编写依赖于精确数据布局的可移植代码很有用,例如传递打包的 RGB 值:
typedef uint8_t RGB[3];
RGB * data = ...;
glColorPointer(3, GL_UNSIGNED_BYTE, 0, data);
(好吧,所以 OpenGL 可以接受步幅值,所以这是一个不好的例子,但你明白了)
就此而言,我假设从广泛的概念(甚至是标准中的示例)您可以使用sizeof 获得数组的元素数量,无论如何这很可能在任何地方都适用 - 是否存在任何已知的情况都不是吗?
【问题讨论】:
-
padding的意思是让数据对齐。在你的情况下,我确信所有 3 的 char 数组的大小都是 3。但是如果你声明一个 int 之后,可能会有 1 或 5 个填充。一个好的 c 编译器不会做额外的工作,使其难以预测。但是如果你在谈论可移植性,我认为最好在目标平台上再次编译代码,或者如果平台有很大差异,则交叉编译。
-
“它没有提供任何细节”——它确实说计算数组中元素的数量。没错,这只是一个例子,而且这些例子并不规范。
-
通过查看后续子句可以间接推断出数组没有这样的填充:“当应用于具有结构或联合类型的操作数时,结果是这样的字节总数一个对象,包括内部和尾随填充。” – 这种对结构和联合中的填充的明确引用,以及在数组的情况下缺乏填充让我相信数组中不能有这样的填充。
-
我无法想象填充数组的意义何在。元素已经正确对齐。
-
@ooga:在一种不允许像 C 那样进行指针操作的语言中,数组填充可能对“金丝雀”有用:如果编译器预先加载了一个数组的空间如果标记数据的已知模式,则可以定期检查此类数据以确保没有发生缓冲区溢出。或者,在某些系统上,可以在任何尝试覆盖进位地址时配置硬件陷阱,尽管此类功能通常仅限于故障排除目的(因为许多平台可用的陷阱数量非常有限)。
标签: c language-lawyer