是否保证 C 中的数组元素将连续存储,没有填充?
Is it guaranteed that array elements in C will be stored consecutively, with no padding?
换句话说:如果我以这种方式分配数组,是否可以保证:
void *arr = calloc(nmemb, sizeof(some_type))
那么elta
、eltb
、eltc
都会指向内存中的同一个位置,也就是这个数组的some_type
类型的第二个元素?
some_type *elta = &((some_type*)arr)[1];
some_type *eltb = ((some_type*)arr)+1;
some_type *eltc = (char*)arr+sizeof(some_type);
我问这个问题的原因是因为我想在 C 中做一个“容器”,如果这不成立,那么我不知道如何 return 一个指针到第一个元素以外的任何其他元素。
是的,有保证。 如果添加了 填充字节,它们将添加到struct some_type
内,但不会添加到两个数组元素之间。
E. g.:
struct S
{
int n;
short s;
// this is just for illustration WHERE byte padding (typically) would occur!!!
#if BYTE_ALIGNMENT >= 4
unsigned char : 0;
unsigned char : 0;
#endif
};
struct S s[2];
size_t d = (char*)(s + 1) - (char*)s;
将字节对齐调整为 4 或 8(或更大的 2 的幂),此结构的大小将为 8,d 也将等于 8,字节对齐设置为 1 或 2,结构将具有大小6 就像 d...
注意:这不是唯一可以出现填充字节的地方:如果您切换成员 n
和 s
,则在 s
和 [= 之间需要填充字节12=] 使 n
正确对齐。另一方面,在 n 之后不再需要填充字节,因为结构大小已经可以确保正确对齐。
参考标准:C11, 6.2.5.20:
An array type describes a contiguously allocated nonempty set of objects with a particular member object type, called the element type. 36) Array types are characterized by their element type and by the number of elements in the array. [...]
(由我突出显示!)。
数据对齐是一件复杂的事情,如下例所示(您甚至可以画出自己的实验):
#include <stdio.h>
struct A { /* no padding */
char a[3];
};
struct B {
int a;
char b[3];
/* one byte of padding (in 32bit arch) added here */
};
struct C { /* no padding again */
char a[4];
char b[3];
};
struct D {
char a[3];
/* one byte of padding to ensure alignment of next field */
int b;
char c[3];
/* one byte of padding to ensure alignment of whole struct in arrays */
}
#define P(X) printf("sizeof struct %s == %ld\n", #X, sizeof (struct X))
int main()
{
P(A);
P(B);
P(C);
P(D);
} /* main */
如您所见,struct A
类型所需的对齐(1 个字节)允许将其放置在内存中的任何位置,并确定不需要填充字节来确定 sizeof
值。
在第二个示例中,我们引入了一个 int
值,它强制整个 struct
进行字对齐(因此可以在正确对齐的内存地址中访问 int)所以这一次,编译器已经(在结构的末尾)填充了额外的字节,因此指定类型的任何数组类型都可以正确对齐,并且可以在有效地址访问其 int
字段。
在第三个示例中,我说明了第二个示例中填充的效果是由于结构中存在 int
字段,因为第三个示例具有相同大小的字段,但是这次一个不需要对齐的字段,所以没有插入填充,因为里面的所有单独的数据类型都需要对齐 1.
输出(在我的系统上,MAC OSX 系统)是:
sizeof struct A == 3
sizeof struct B == 8
sizeof struct C == 7
sizeof struct D == 12
换句话说:如果我以这种方式分配数组,是否可以保证:
void *arr = calloc(nmemb, sizeof(some_type))
那么elta
、eltb
、eltc
都会指向内存中的同一个位置,也就是这个数组的some_type
类型的第二个元素?
some_type *elta = &((some_type*)arr)[1];
some_type *eltb = ((some_type*)arr)+1;
some_type *eltc = (char*)arr+sizeof(some_type);
我问这个问题的原因是因为我想在 C 中做一个“容器”,如果这不成立,那么我不知道如何 return 一个指针到第一个元素以外的任何其他元素。
是的,有保证。 如果添加了 填充字节,它们将添加到struct some_type
内,但不会添加到两个数组元素之间。
E. g.:
struct S
{
int n;
short s;
// this is just for illustration WHERE byte padding (typically) would occur!!!
#if BYTE_ALIGNMENT >= 4
unsigned char : 0;
unsigned char : 0;
#endif
};
struct S s[2];
size_t d = (char*)(s + 1) - (char*)s;
将字节对齐调整为 4 或 8(或更大的 2 的幂),此结构的大小将为 8,d 也将等于 8,字节对齐设置为 1 或 2,结构将具有大小6 就像 d...
注意:这不是唯一可以出现填充字节的地方:如果您切换成员 n
和 s
,则在 s
和 [= 之间需要填充字节12=] 使 n
正确对齐。另一方面,在 n 之后不再需要填充字节,因为结构大小已经可以确保正确对齐。
参考标准:C11, 6.2.5.20:
An array type describes a contiguously allocated nonempty set of objects with a particular member object type, called the element type. 36) Array types are characterized by their element type and by the number of elements in the array. [...]
(由我突出显示!)。
数据对齐是一件复杂的事情,如下例所示(您甚至可以画出自己的实验):
#include <stdio.h>
struct A { /* no padding */
char a[3];
};
struct B {
int a;
char b[3];
/* one byte of padding (in 32bit arch) added here */
};
struct C { /* no padding again */
char a[4];
char b[3];
};
struct D {
char a[3];
/* one byte of padding to ensure alignment of next field */
int b;
char c[3];
/* one byte of padding to ensure alignment of whole struct in arrays */
}
#define P(X) printf("sizeof struct %s == %ld\n", #X, sizeof (struct X))
int main()
{
P(A);
P(B);
P(C);
P(D);
} /* main */
如您所见,struct A
类型所需的对齐(1 个字节)允许将其放置在内存中的任何位置,并确定不需要填充字节来确定 sizeof
值。
在第二个示例中,我们引入了一个 int
值,它强制整个 struct
进行字对齐(因此可以在正确对齐的内存地址中访问 int)所以这一次,编译器已经(在结构的末尾)填充了额外的字节,因此指定类型的任何数组类型都可以正确对齐,并且可以在有效地址访问其 int
字段。
在第三个示例中,我说明了第二个示例中填充的效果是由于结构中存在 int
字段,因为第三个示例具有相同大小的字段,但是这次一个不需要对齐的字段,所以没有插入填充,因为里面的所有单独的数据类型都需要对齐 1.
输出(在我的系统上,MAC OSX 系统)是:
sizeof struct A == 3
sizeof struct B == 8
sizeof struct C == 7
sizeof struct D == 12