C 中的数组元素计数
Array element count in C
我一直使用以下范例迭代 C 中的静态定义数组:
struct foo { ... };
struct foo array[10];
for (int i; i < sizeof(array) / sizeof(array[0]); i++)
...
而且,到目前为止,这每次都有效 ;-)
但这让人感到奇怪,如果结构的实际长度不是自然对齐的,这会不会中断,例如:
struct foo { long a; char b; };
由于对齐(LP64 数据模型),编译器不应该决定 sizeof(struct foo) == 7
而 sizeof(array) == 32
吗?
没有
数组中没有"dead space";如果有填充,包含 struct
大小。
sizeof
宏 returns 结构的大小 包括 所有填充。这对于 struct
的静态定义数组仍然适用。所以声明:
sizeof(struct array) / sizeof(struct array[0])
无论每个结构元素中有多少成员或什么类型的成员,都将始终允许您遍历数组元素。
Packing/alignment 对数组边界没有影响
即使 pragma pack 指令在您的源代码中使用,也可能导致包装发生变化(这也会影响对齐),从而导致数组的每个结构元素的 sizeof 值不同,数组元素的数量保持不变。
...或者 counter-example 如果我的假设并不总是成立
注意事项:
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])
将不再为您提供正确的数组元素数。
成员的结构内部对齐对该结构的数组没有影响。因此,无论结构包含哪些成员或它们如何对齐,您所拥有的都可以保证工作。
如果结构成员之间有一个填充,那么所有结构数组的元素都是一样的。 sizeof(array)
总是能被 sizeof(array[0])
整除。
所以计算数组大小的方法,
size_t len = sizeof(array)/sizeof(array[0]);
保证适用于 any 类型,只要 array
一个 array.
正如 C99 standard, section 6.5.3.4 关于 sizeof
运算符的说明:
When applied to an operand that has array type, the result is the
total number of bytes in the array.
并且:
EXAMPLE 2 Another use of the sizeof operator is to compute the number
of elements in an array:
`sizeof array / sizeof array[0]`
所以数组的大小总是是其元素大小的倍数。
关于结构的同一段落:
When applied to an operand that has structure or union type, the
result is the total number of bytes in such an object, including
internal and trailing padding.
编译器可以自由地在结构中成员之间和末尾的任何位置插入填充,但第一个成员的偏移量必须始终为零。
另一方面,数组必须始终是连续的,元素之间没有任何 "gaps"。该标准规定:
An array type describes a contiguously allocated nonempty set of objects
通常,大多数编译器会在结构的末尾插入一些填充,以确保在数组中连续布局时,第二个元素不会破坏某些成员的对齐要求。典型的规则是结构的总大小必须扩展到可以被具有最大对齐要求的成员的对齐整除的大小。
在 LP64 模型中,sizeof(long)
是 8,sizeof(char)
是 1。long
需要 8 字节对齐,char
没有对齐要求。大小之和为 9
,但编译器会将结构的大小扩展到 16,因此 16 % 8 == 0
。这样,相邻的数组元素将从可被 8
整除的位置开始,因此将保留第一个成员的对齐方式。
我一直使用以下范例迭代 C 中的静态定义数组:
struct foo { ... };
struct foo array[10];
for (int i; i < sizeof(array) / sizeof(array[0]); i++)
...
而且,到目前为止,这每次都有效 ;-)
但这让人感到奇怪,如果结构的实际长度不是自然对齐的,这会不会中断,例如:
struct foo { long a; char b; };
由于对齐(LP64 数据模型),编译器不应该决定 sizeof(struct foo) == 7
而 sizeof(array) == 32
吗?
没有
数组中没有"dead space";如果有填充,包含 struct
大小。
sizeof
宏 returns 结构的大小 包括 所有填充。这对于 struct
的静态定义数组仍然适用。所以声明:
sizeof(struct array) / sizeof(struct array[0])
无论每个结构元素中有多少成员或什么类型的成员,都将始终允许您遍历数组元素。
Packing/alignment 对数组边界没有影响
即使 pragma pack 指令在您的源代码中使用,也可能导致包装发生变化(这也会影响对齐),从而导致数组的每个结构元素的 sizeof 值不同,数组元素的数量保持不变。
...或者 counter-example 如果我的假设并不总是成立
注意事项:
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])
将不再为您提供正确的数组元素数。
成员的结构内部对齐对该结构的数组没有影响。因此,无论结构包含哪些成员或它们如何对齐,您所拥有的都可以保证工作。
如果结构成员之间有一个填充,那么所有结构数组的元素都是一样的。 sizeof(array)
总是能被 sizeof(array[0])
整除。
所以计算数组大小的方法,
size_t len = sizeof(array)/sizeof(array[0]);
保证适用于 any 类型,只要 array
一个 array.
正如 C99 standard, section 6.5.3.4 关于 sizeof
运算符的说明:
When applied to an operand that has array type, the result is the total number of bytes in the array.
并且:
EXAMPLE 2 Another use of the sizeof operator is to compute the number of elements in an array:
`sizeof array / sizeof array[0]`
所以数组的大小总是是其元素大小的倍数。
关于结构的同一段落:
When applied to an operand that has structure or union type, the result is the total number of bytes in such an object, including internal and trailing padding.
编译器可以自由地在结构中成员之间和末尾的任何位置插入填充,但第一个成员的偏移量必须始终为零。
另一方面,数组必须始终是连续的,元素之间没有任何 "gaps"。该标准规定:
An array type describes a contiguously allocated nonempty set of objects
通常,大多数编译器会在结构的末尾插入一些填充,以确保在数组中连续布局时,第二个元素不会破坏某些成员的对齐要求。典型的规则是结构的总大小必须扩展到可以被具有最大对齐要求的成员的对齐整除的大小。
在 LP64 模型中,sizeof(long)
是 8,sizeof(char)
是 1。long
需要 8 字节对齐,char
没有对齐要求。大小之和为 9
,但编译器会将结构的大小扩展到 16,因此 16 % 8 == 0
。这样,相邻的数组元素将从可被 8
整除的位置开始,因此将保留第一个成员的对齐方式。