我正在阅读由维基百科链接的this version of the C99 standard,试图了解阵列成员的灵活性。
在6.7.2.1节中,声明了这个结构:
struct s { int n; double d[]; };
给出了一个例子:
s1 = malloc(sizeof (struct s) + 10);
s2 = malloc(sizeof (struct s) + 6);
它说s1
和s2
的行为就像宣言是:
struct { int n; double d[1]; } *s1, *s2;
它列出了一些你可以做的事情:
double *dp;
dp = &(s1->d[0]); // valid
*dp = 42; // valid
dp = &(s2->d[0]); // valid
*dp = 42; // undefined behavior
我可以看到为什么上面的最后一行是未定义的,因为s2
只分配了6个额外的字节,这不足以存储一个double,但是我不明白为什么会说这个行为s1
和s2
如果被声明为:
struct { int n; double d[1]; } *s1, *s2;
当s2
似乎没有分配足够的内存来存储该结构时。
该文件似乎是某种草案,所以我不确定是否存在错误,或者我是否误解了其含义。
答案 0 :(得分:1)
(你不应该再看C99了,它已经过时了.C11是你引用的同一个地方的n1570文件。很可能/希望很快被C17取代。)
我认为原因是它表现得好像有一个元素就是短语
如果它没有元素,那么这样的数组就好像它有一个元素一样 如果尝试访问该元素,则行为未定义...
答案 1 :(得分:0)
我喜欢在C99中像C ++中的虚拟类一样处理灵活的结构,你可以指出它们但你不应该实例化它们。我经常构建一个辅助函数(工厂助手?),它获取灵活数组中存储的项目数,并返回结构所需的实际分配,以确保它清楚意图。
#define OBJECTS_NEEDED 10
typedef struct
{
uint8_t val1;
uint32_t val2; // probable forces 4byte alignment of structure
} myObject_t;
typedef struct
{
uint8_t allocatedObjects;
uint16 someMetaData;
myObject_t objects[]; // struct inherits worst case alignment rule
} myObjectSet_t;
size_t getMyObjectSetSize(uint8_t reqObjs)
{
return sizeof(myObjectSet_t) + reqObjs * sizeof(myObject_t);
}
void initMyObjectSetSize(myObjectSet_t *mySet, uint8_t reqObjs)
{
mySet->allocatedObjects = reqObjs;
// Other Init code .....
}
void main()
{
myObjectSet_t *mySet = malloc(getMyObjectSetSize(OBJECTS_NEEDED));
initMyObjectSetSize(mySet , OBJECTS_NEEDED);
// One issue, you can't rely on structure padding to be the same
// from machine to machine so this test may fail on one compiler
// and pass on another. You really do nee to use offsetof() if
// you need to find address of mySet given the address of one
// of the objects[]
assert((void*)mySet->objects == (void*)(mySet + 1));
}
编译器知道sizeof(myObjectSet_t)至少需要为mod 4,因为myObject_t数组可能需要至少32位对齐。我已经看到在Windows上运行的GNU编译器生成与在同一台笔记本电脑上的虚拟机中运行的GNU编译器不同的填充。