2016-01-14 47 views
6

我一直使用以下范例用于遍历静态定义的数组在C:数组元素计数用C

struct foo { ... }; 
struct foo array[10]; 

for (int i; i < sizeof(array)/sizeof(array[0]); i++) 
    ... 

的,那么,这个工作每次到目前为止;-)

但它使奇迹,可这不破,如果结构实际上是长度不自然对齐,例如:

struct foo { long a; char b; }; 

不应该编译器决定sizeof(struct foo) == 7虽然sizeof(array) == 32由于对齐(LP64数据模型)?

+0

如果我的假设是真实的,我正在寻找一个规范的参考,或者如果我的假设并不总是成立的话,我会找一个反例。 –

+1

BTW是一个整数除法,它不能给你错误的数字。我错了吗? – LPs

+0

“_S不应该由编译器决定'sizeof(struct foo)== 7'_”不一定,可以有填充。 – emlai

回答

5

如约sizeof操作者的C99 standard, section 6.5.3.4状态:

当应用于具有数组类型的操作数,其结果是该阵列中的字节 总数。

和:

实施例2 sizeof运算符的另一个用途是计算元件的阵列中的数 :

 `sizeof array/sizeof array[0]` 

所以阵列的大小将总是是其元素大小的倍数。

和约结构相同的段:

当施加到具有结构或联合类型的操作数时, 结果是字节的总数在这样一个对象,包括 内部和后填充。

+1

同样来自标准:“当应用于具有结构或联合类型的操作数时,结果是此类对象中的总字节数**,包括内部和尾部填充**” – dbush

+1

@dbush将它添加到答案如果你不介意.. –

4

数组中没有“死区”如果有填充,则包含,其中的大小为struct

+0

看起来你是对的钱,我可以用gcc的'__attribute __((packed))'来调整结构大小,例如'__attribute __((aligned(128)))'但是无论我对数组做什么,它都是数组的常量倍数。 –

1

sizeof宏返回您的结构的大小包括所有填充。对于静态定义的struct数组,这仍然是正确的。所以声明:

sizeof(struct array)/sizeof(struct array[0]) 

无论每个struct元素中有多少个或什么类型的成员,总会允许您遍历数组元素。

包装/对准使得对于数组边界
没有差别,即使pragma pack指令在源所使用的,可能导致包装改变(这也可以影响对准),从而产生一个不同的值对于数组中的每个结构元素的sizeof,数组元素的计数保持不变

...或者一个反例,如果我的假设并不总是持有

要注意这一点很重要
sizeof运营工作不同的阵列结构的(或任何其他类型),实际上是指针,在堆上动态创建。例如,如果您有:

typedef struct { ... }FOO; 
FOO *foo; 
... 
foo = malloc(10*sizeof(FOO)); 
size_t size = sizeof(foo); //returns sizeof pointer, (4 bytes on 32 bit target) 
          //No matter how many, or what type members make up the struct 

因此

sizeof(struct foo)/sizeof(struct foo[0]) 

将不再给你数组元素的正确计数。

2

成员的结构内部对齐不会影响该结构的数组。因此,不管结构体包含什么成员或它们是如何对齐的,你拥有的东西都可以保证工作。

如果有该结构的构件之间的填充,那么它的对所有结构阵列的元件是相同的。 sizeof(array)总是可以被sizeof(array[0])整除。

所以计算阵列大小的方法中,

size_t len = sizeof(array)/sizeof(array[0]); 

保证只要array一个阵列任何类型工作。

1

编译器可以自由地在成员之间和结尾处的结构体中插入填充,但第一个成员的偏移必须始终为零。

另一方面,阵列总是必须是连续的,元素之间没有任何“空白”。该标准规定:

数组类型描述了连续分配的非空的对象集

通常,大多数编译器将在结构的末尾插入一些填充,以确保当连续布局在数组中,第二个元素不会破坏某些成员的对齐要求。典型的规则是结构的总大小必须扩展到可以通过最大对齐要求的成员对齐平均分配的大小。

在LP64模式,sizeof(long)是8和sizeof(char)是1 long将需要8字节对齐,char没有对齐要求。大小的总和应为9,但编译器会将结构的大小扩展到16,因此16 % 8 == 0。这样,一个相邻的数组元素将从一个可以被8整除的位置开始,所以第一个成员的对齐将被保留。