1

GCC 编译函数返回一个具有灵活数组成员的结构。该标准在 6.7.2.1 中给出了如何处理此类结构的定义:

在大多数情况下,灵活数组成员被忽略。特别是,结构的大小就像省略了柔性数组成员一样,只是它可能具有比省略所暗示的更多的尾随填充。

由于具有灵活数组成员的结构的大小是已知的,因此根据 6.2.5 中给出的完整性定义,该类型是完整的:

在翻译单元内的不同点,对象类型可能是不完整的(缺乏足够的信息来确定该类型对象的大小)或完整的(具有足够的信息)。37)

另外,6.5.2.2

表示被调用函数的表达式 96) 应具有指向返回 void 或返回数组类型以外的完整对象类型的函数的类型指针。

所以struct用灵活的数组成员返回 s 应该是合法的。


如何修复下面的示例以使其正常工作(我需要具有灵活数组成员的堆栈分配结构):

#include <stdio.h>

struct test{
    size_t sz;
    char data[];
};

struct test get_test(void){
    int sz = 5;
    char data[5] = "test";
    struct test test = {.sz = 5};
    //How to copy char data[5] into the struct test test?
    return test;
}

int main(void){
    struct test tst = get_test();
    printf("%s\n", tst.data);
}
4

2 回答 2

4

如何修复下面的示例以使其正常工作(我需要具有灵活数组成员的堆栈分配结构):

灵活数组成员允许对结构和 FAM 进行单一动态分配。(你不能有一个堆栈分配结构和动态FAM——如果你想这样做,不要使用FAM,data而是使用一个指针。)要分配和利用FAM,你需要改变你的功能返回一个指向类型struct test(例如struct test*)的指针,然后为"test"in的结构和存储声明和分配存储,get_test并返回一个指向已分配块的指针,例如

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

struct test {
    size_t sz;
    char data[];
};

struct test *get_test (void)    /* declare as type struct test* */
{
    size_t sz = 5;
    char data[] = "test";

    /* allocate storage for struct + FAM */
    struct test *test = malloc (sizeof *test + sizeof data);
    if (!test)
        return NULL;

    test->sz = sz;                              /* assign sz */
    memcpy (test->data, data, sizeof data);     /* copy data */

    return test;
}

int main (void) {

    struct test *tst = get_test();

    printf ("test->sz   : %zu\ntest->data : %s\n", tst->sz, tst->data);

    free (tst);     /* don't forget to free what you allocate */
}

示例使用/输出

$ ./bin/fam
test->sz   : 5
test->data : test
于 2019-10-14T06:48:46.973 回答
3

是的,返回这样的值是有效的 C,但不会复制任何数组元素。自动变量的行为就好像它确实分配了一个长度为 1 的数组(因为 0 的数组长度在标准 C 中无效),但访问.data[0]将具有 UB - 对象的实际大小可能包括.data[0],甚至更多连续的元素 - 或者不是。(C11 6.7.2.1p18)。

不可能在标准 C中定义一个在灵活数组成员中包含任何内容的自动变量(扩展可能并且确实存在)!

赋值也是有效的(因此也返回),但是灵活的数组成员在赋值后将再次包含不确定的值(C11 6.7.2.1p25)。

于 2019-10-14T06:37:08.797 回答