Как я могу инициализировать гибкий массив в родате и создать указатель на него в C? - PullRequest
2 голосов
/ 26 сентября 2019

В C код

char *c = "Hello world!";

сохраняет Hello world!\0 в родате и инициализирует c указателем на него.Как я могу сделать это с чем-то, кроме строки?

В частности, я пытаюсь определить свой собственный тип строки

typedef struct {
   size_t Length;
   char Data[];
} PascalString;

И затем хочу какой-то макрос, чтобы я мог сказать

const PascalString *c2 = PASCAL_STRING_CONSTANT("Hello world!");

И пусть он ведет себя так же, в нем \x0c\0\0\0Hello world! хранится в родате и c2 инициализируется указателем на него.

Я пытался использовать

#define PASCAL_STRING_CONSTANT(c_string_constant) \
    &((const PascalString) { \
        .Length=sizeof(c_string_constant)-1, \
        .Data=(c_string_constant), \
    })

, как предложено в этих вопросов , но это не работает, потому что Data является гибким массивом: я получаю ошибку error: non-static initialization of a flexible array member (с gcc, clangвыдает похожую ошибку).

Возможно ли это в C?И если да, то как будет выглядеть макрос PASCAL_STRING_CONSTANT?

Ответы [ 2 ]

0 голосов
/ 26 сентября 2019

Вы можете использовать этот макрос, который называет имя переменной по своему содержанию:

#define PASCAL_STRING(name, str) \
    struct { \
        unsigned char len; \
        char content[sizeof(str) - 1]; \
    } name = { sizeof(str) - 1, str }

Для создания такой строки.Используйте это так:

const PASCAL_STRING(c2, "Hello world!");
0 голосов
/ 26 сентября 2019

Это может быть сделано с расширением statment-expression GNU, хотя оно нестандартно.

#define PASCAL_STRING_CONSTANT(c_string_constant) ({\
        static const PascalString _tmpstr = { \
            .Length=sizeof(c_string_constant)-1, \
            .Data=c_string_constant, \
        }; \
        &_tmpstr; \
    })

Расширение позволяет вам иметь несколько операторов в блоке как выражение, котороеоценивает значение последнего оператора, заключая блок в ({ ... }).Таким образом, мы можем объявить нашу PascalString как статическое константное значение, а затем вернуть указатель на него.

Для полноты мы можем также создать буфер стека, если мы хотим изменить его:

#define PASCAL_STRING_STACKBUF(initial_value, capacity) \
    (PascalString *)&(struct { \
        uint32_t Length; \
        char Data[capacity]; \
    }){ \
        .Length = sizeof(initial_value)-1, \
        .Data = initial_value, \
    }
...