2014-11-23 84 views
5

很明显,在C cannot insert padding between their elements中的数组。但是,是否有任何规则说他们不能在整个阵列的尾端处添加尾部填充?数组可以有尾部填充吗?

即,这个程序保证在任何地方都能得到相同的结果吗?

#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]仍然恰好映射到*(&b + sizeof(a) * 1 + 1)不管其包含的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); 

(OK这样的OpenGL可以接受步幅值,所以这是一个坏榜样,但你明白了吧)

对于这个问题,我从广泛的概念(即使假设标准中的例子),你可以用sizeof得到一个数组元素的数量,无论如何这在任何地方都可能是真的 - 是否有任何已知的情况?

+0

填充的含义是使数据对齐。在你的情况下,我相信所有3的char数组的大小都是3,但如果你在之后声明一个int,那么可能会有1或5个填充。一个好的c编译器不会做额外的工作,这很难预测。但如果您谈论的是可移植性,我认为最好是在目标平台上重新编译代码,或者如果平台差异很大,则可以进行交叉编译。 – HuStmpHrrr 2014-11-23 19:36:48

+0

“,并没有给出任何细节” - 它确实说计算数组中的元素数量。你说得对,那只是一个例子,而这个例子并不是规范的。 – hvd 2014-11-23 19:39:26

+0

通过查看后续子句,可以间接推断出数组没有这种填充:“当应用于具有结构或联合类型的操作数时,结果是此类对象中的总字节数,包括内部和尾部填充。” - 在结构和联合中显式引用了填充,而在数组中缺少这种引用使我相信数组中不能有这种填充。 – 2014-11-23 19:41:32

回答

6

我认为标准从未认为有必要明确说明数组没有填充,因为简单的理由是这样的填充对于任何实现都是有用的。

也就是说,我确实相信标准通过==运算符的描述禁止这种填充。

6.5.9相等运算

语义

6两个指针比较相等当且仅当[...]或一个是一个指针 到一个过去的端部一个数组对象,另一个是指向不同数组对象的开始的指针,该对象恰好紧跟地址空间中的第一个数组对象。

鉴于

int array[2][2]; 

表达&array[0][2]点是一个指针一个过去的第一阵列子对象的端部。 &array[1][0]是一个指向第二个数组子对象的指针,它紧跟在内存中的第一个数组之后。这些指针需要比较相等。如果int[2]有尾部填充,如果sizeof(int[2]) > 2 * sizeof(int),我无法想象任何实现如何使两个指针比较相等。

+0

斑点,+1。 – 2014-11-23 19:54:08