Разрешено ли возвращение структуры с гибким членом массива? - PullRequest
1 голос
/ 14 октября 2019

Функция компиляции 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);
}

Ответы [ 2 ]

4 голосов
/ 14 октября 2019

Как исправить приведенный ниже пример, чтобы он работал должным образом (мне нужна структура, выделенная стеком с гибким элементом массива):

Гибкий член массива допускает одно динамическое распределение обоихструктура и FAM. (Вы не можете иметь выделенную структуру стека и динамическую FAM - если вы хотите это сделать, не используйте FAM, вместо этого используйте указатель для data.) Чтобы выделить и использовать FAM, вам нужно изменитьВаша функция возвращает указатель на тип struct test (например, struct test*), а затем объявляет и выделяет хранилище для вашей структуры и хранилища для "test" в 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
3 голосов
/ 14 октября 2019

Да, это действительно C для возврата такого значения, но ни один из элементов массива не будет скопирован. Автоматическая переменная будет вести себя так, как если бы она выделялась массивом длины 1 (поскольку длина массива 0 недопустима в стандарте C), но доступ к .data[0] будет иметь UB - фактический размер изобъект может включать .data[0] и, возможно, даже более последовательные элементы - или не включать. ( C11 6.7.2.1p18 ).

Невозможно определить автоматическую переменную, которая быиметь какой-либо контент в элементе гибкого массива в стандарте C (расширения могут и существуют)!

Назначение также допустимо (и, следовательно, также возвращается), но снова член гибкого массива будетсодержат неопределенные значения ( C11 6.7.2.1p25 ) после присвоения.

...