简体   繁体   English

如何均匀地分配具有灵活数组成员的结构体数组?

[英]How to allocate an array of structs with flexible array members comformingly?

I have the following struct with a flexible array member: 我有以下具有灵活数组成员的结构:

struct test {
    size_t sz;
    const char str[];
};

Now I want to allocate some memory to put this struct continuously (like in array). 现在,我想分配一些内存以连续放置此结构(例如在数组中)。 The problem is a declaration like struct test test_arr[] is undefined behavior. 问题是像struct test test_arr[]这样的声明struct test test_arr[]是未定义的行为。 6.7.2.1(p3) : 6.7.2.1(p3)

the last member of a structure with more than one named member may have incomplete array type; 具有多个命名成员的结构的最后一个成员可能具有不完整的数组类型; such a structure (and any union containing, possibly recursively, a member that is such a structure) shall not be a member of a structure or an element of an array. 这样的结构(以及任何可能包含递归的此类结构的并集的联合)不应是结构的成员或数组的元素。

We know that pointer returned by malloc can be converted to a pointer to any objecut type with fundamental alignment. 我们知道, malloc返回的指针可以转换为具有基本对齐方式的任何对象类型的指针。 Consider the following code: 考虑以下代码:

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 

What is the conforming way of doing so? 这样做的遵循方式是什么?

A struct with a flexible array member can't be a member of an array, as dictated by the quote you gave. 正如您所引用的那样,具有灵活数组成员的struct不能是数组的成员。

The best way to handle this is to change the flexible array member to a pointer and allocate space for it separately. 解决此问题的最佳方法是将灵活数组成员更改为指针,并为其单独分配空间。

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';

Also, it's generally not a good idea to have const members of a struct. 另外,拥有const成员通常不是一个好主意。

A "popular extension" which most implementations can be configured to support (if they don't always do so) is to allow the address of structure type to be converted to the address of another which shares a Common Initial Sequence, and be used to access members of that sequence, until the structure is accessed via means other than the converted pointer, or execution enters a function or loop wherein that would occur. 大多数实现都可以配置为支持的“通用扩展名”(如果并非总是如此)是允许将结构类型的地址转换为共享公共初始序列的另一个地址,并用于访问该序列的成员,直到通过除转换后的指针以外的其他方式访问该结构,或者执行进入其中可能发生的函数或循环。

On implementations that support that extension, the requested semantics can be achieved by declaring a structure whose layout which matches that of the structure with the Flexible Array Member. 在支持该扩展的实现中,可以通过声明结构的布局与“灵活数组成员”的结构匹配的结构来实现所请求的语义。 For example: 例如:

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);
}

Some compilers like icc and MSVC are sophisticated enough to support this extension even when type-based aliasing is enabled. 即使启用了基于类型的别名,某些编译器(如icc和MSVC)也足以支持此扩展。 Others like gcc and clang can only support this extension via the use of the -fno-strict-aliasing option. 其他诸如gcc和clang只能通过使用-fno-strict-aliasing选项来支持此扩展。

Although code using this extension is not strictly conforming, the Standards Committee has said in the published Rationale that they did not want to make the language usable only for writing portable programs. 尽管使用此扩展名的代码不严格符合标准,但是标准委员会在已发布的Rationale中表示,他们不想使该语言仅可用于编写可移植程序。 Instead, they expected that quality implementations would support a variety of "popular extensions" by processing some constructs in ways that would be useful to their customers even when the Standard would allow them to do otherwise. 相反,他们希望质量实现通过以对客户有用的方式处理某些构造来支持各种“流行扩展”,即使标准允许他们这样做。 The ability to convert pointers among structure types has been a fundamental part of the language the Standard was written to describe since 1974, and nearly all implementations can be configured to support it. 自1974年以来,在结构类型之间转换指针的能力一直是该标准所描述语言的基本组成部分,几乎所有实现都可以配置为支持该语言。 Code like the above should thus be recognized as more portable than code which relies upon non-standard syntactical extensions to achieve similar semantics. 因此,与依赖非标准语法扩展来实现相似语义的代码相比,上述代码应被认为具有更高的可移植性。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM