Гибкий член массива безымянной структуры - PullRequest
1 голос
/ 13 мая 2019

Рассмотрим следующий пример:

typedef struct test_flex_arr{
    size_t sz;
    struct {
        int i;
        const char *path;
    } info[];
} tfa;

int main(void){
    size_t sz = 100;
    tfa *ptr = malloc(sizeof *ptr + sizeof (*((tfa*) NULL)).info[sz]);
    ptr->info[99].i = 10;
    printf("%d\n", ptr->info[99].i); //prints 10
}

DEMO

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

Оператор sizeof возвращает размер (в байтах) своего операнда, который может быть выражением или именем типа в скобках.Размер определяется по типу операнда.Результатом является целое число. Если тип операнда является типом массива переменной длины, операнд оценивается ;в противном случае операнд не оценивается, и результатом является целочисленная константа

Тип операнда sizeof ((*((tfa*) NULL)).info)[sz] является массивом переменной длины, поэтому операнд должен быть оценен.Но оценка операнда означает разыменование NULL, которое, как я ожидал, приведет к сбою.

Хорошо ли определено поведение кода?

1 Ответ

8 голосов
/ 14 мая 2019

(*((tfa*) NULL)).info[sz] не является типом массива переменной длины, потому что (*((tfa*) NULL)).info не является типом.

Так что это рассматривается как обычное выражение, ссылающееся на элемент sz массива (*((tfa*) NULL)).info. Согласно приведенной спецификации, это не оценивается, поэтому тот факт, что он разыменовывает NULL, не вызывает неопределенного поведения. Он просто возвращает размер элемента массива, который не зависит от расположения массива или индекса. Вот почему он компилируется без предупреждения и не падает.

Но это не дает желаемого результата. Вы получаете только размер одного элемента массива, а не sz элементов, для которых вам действительно нужно выделить место. Вам нужно умножить размер элемента на количество элементов. Так что используйте

tfa *ptr = malloc(sizeof *ptr + sz * sizeof ptr->info[0]);
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...