我具有以下带有灵活数组成员的结构:
struct test {
size_t sz;
const char str[];
};
现在,我想分配一些内存以连续放置此结构(例如在数组中)。问题是像struct test test_arr[]
这样的声明是未定义的行为。 6.7.2.1(p3)
:
具有多个命名成员的结构的最后一个成员 可能具有不完整的数组类型;这样的结构(以及任何联盟 包含(可能是递归的)具有这种结构的成员) 不得是结构的成员或数组的元素。
我们知道malloc
返回的指针可以转换为指向任何具有基本对齐方式的对象类型的指针。考虑以下代码:
void *obj= malloc(100 * sizeof(struct test)); //enough memory
struct test *t1 = obj;
t1 -> sz = 2;
t1 -> str = {'a', 'b'};
struct test *t2 = (void *) (((char *) obj) + sizeof(struct test) + sizeof(char[2])); // non conforming
这样做的遵循方式是什么?
答案 0 :(得分:3)
根据您提供的引号,具有灵活数组成员的<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
<uses-feature android:name="android.hardware.location.gps" />
不能是数组的成员。
处理此问题的最佳方法是将灵活数组成员更改为指针并为其单独分配空间。
struct
此外,拥有struct test {
size_t sz;
char *str;
};
...
struct test *arr = malloc(100 * sizeof(struct test));
arr[0].sz = 2;
arr[0].str = malloc(2);
arr[0].str[0] = 'a';
arr[0].str[1] = 'b';
arr[1].sz = 3;
arr[1].str = malloc(3);
arr[1].str[0] = 'c';
arr[1].str[1] = 'd';
arr[1].str[2] = 'e';
个结构成员通常也不是一个好主意。
答案 1 :(得分:1)
大多数实现都可以配置为支持的“通用扩展名”(如果并非总是如此)是允许将结构类型的地址转换为共享公共初始序列的另一个地址,以及用于访问该序列的成员,直到通过除转换后的指针以外的其他方式访问该结构,或执行进入其中可能会发生的函数或循环。
在支持该扩展的实现上,可以通过声明结构的布局与“灵活数组成员”的结构匹配的结构来实现所请求的语义。例如:
struct POINT { int x, y; };
struct POLYGON { int sides; struct POINT coords[]; };
struct TRIANGLE { int sides; struct POINT coords[3]; };
void draw_polygon(struct POLYGON const *p);
void test(void)
{
struct TRIANGLE my_triangle = {3, {{1,2}, {3,4], {5,6}};
draw_polygon((struct POLYGON*)&my_triangle);
}
即使启用了基于类型的别名,诸如icc和MSVC之类的某些编译器也足以支持此扩展。其他诸如gcc和clang只能通过使用-fno-strict-aliasing
选项来支持此扩展。
尽管使用此扩展名的代码不严格符合标准,但标准委员会在已发布的《基本原理》中表示,他们不想使该语言仅可用于编写可移植程序。相反,他们希望质量实现通过以对客户有用的方式处理某些构造来支持各种“流行扩展”,即使标准允许他们这样做。自1974年以来,在结构类型之间转换指针的能力一直是该标准所描述语言的基本组成部分,几乎所有实现都可以配置为支持该语言。因此,与依赖非标准语法扩展来实现相似语义的代码相比,上述代码应具有更高的可移植性。