Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/c/60.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C 如何协调地分配具有灵活数组成员的结构数组?_C_Language Lawyer_Flexible Array Member - Fatal编程技术网

C 如何协调地分配具有灵活数组成员的结构数组?

C 如何协调地分配具有灵活数组成员的结构数组?,c,language-lawyer,flexible-array-member,C,Language Lawyer,Flexible Array Member,我有以下带有灵活数组成员的结构: struct test { size_t sz; const char str[]; }; 现在我想分配一些内存来连续放置这个结构(就像在数组中)。问题是类似于struct test\u arr[]的声明是未定义的行为6.7.2.1(p3): 具有多个命名成员的结构的最后一个成员 可能有不完整的数组类型;这样的结构(以及任何联盟) (可能递归地包含这样一个结构的成员) 不得为结构件或阵列元件 我们知道,malloc返回的指针可以转换为指向任何具

我有以下带有灵活数组成员的结构:

struct test {
    size_t sz;
    const char str[];
};
现在我想分配一些内存来连续放置这个结构(就像在数组中)。问题是类似于
struct test\u arr[]
的声明是未定义的行为<代码>6.7.2.1(p3):

具有多个命名成员的结构的最后一个成员 可能有不完整的数组类型;这样的结构(以及任何联盟) (可能递归地包含这样一个结构的成员) 不得为结构件或阵列元件

我们知道,
malloc
返回的指针可以转换为指向任何具有基本对齐方式的objecut类型的指针。考虑下面的代码:

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 

这样做的一致性方法是什么?

具有灵活数组成员的
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';
另外,通常让结构的
const
成员不是一个好主意。

大多数实现可以配置为支持的“流行扩展”(如果它们不总是这样做)是允许将结构类型的地址转换为共享公共初始序列的另一个地址,和用于访问该序列的成员,直到通过转换指针以外的方式访问该结构,或者执行进入将发生这种情况的函数或循环

在支持该扩展的实现上,可以通过声明一个布局与灵活数组成员的结构相匹配的结构来实现所请求的语义。例如:

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年以来,在结构类型之间转换指针的能力一直是该标准所描述语言的一个基本部分,几乎所有的实现都可以配置为支持它。因此,与依赖非标准语法扩展来实现类似语义的代码相比,上述代码应该被认为是更具可移植性的。

struct test*myText=malloc(size*sizeof(*myText))?或者更重要的是,您试图解决的实际问题是什么?@Broman,没问题。但是这个呢:
struct test*myStruct=myText+1
@Broman从
inotify
文件描述符文件读取缓冲区中提供的
struct inotify\u事件
,该事件包含灵活的数组成员。因此,从
malloc
开始,为对象或对象数组分配资源是不可能的。对吗?@SomeName它不是关于
malloc
而是关于指针算法。因为每个结构都可以有不同的大小,所以数组无法正常索引。同意,因为指针算法只在同一数组的元素上定义得很好,谢谢。我会讨论禁用严格别名以访问不兼容结构类型的公共initiail序列。将这两种类型都作为联合成员,并从
联合
声明可见的任何地方访问它们的公共初始序列是一种一致的方式,不是吗?@SomeName:在gcc/clang解释下,不支持获取联合成员的地址并使用结果指针的操作*,即使在获取地址和使用指针之间没有其他内容访问存储的情况下也是如此。甚至像
*(someUnion.memberofarray类型+索引)
这样的东西也可能失败。该标准并没有禁止这种行为,因为作者希望编译器编写者将规则的应用限制在涉及看似不相关对象的别名的情况下。更一般地说,该标准故意允许……专门用于狭义目的的实现以有利于这些目的的方式运行,即使这会使它们不适合于许多其他目的。因此,它不会试图判断哪些行为可能导致实现不适合任何目的。