Оператор sizeof с типом массива переменной длины

Согласно cppreference:

Если тип выражения является типом массива переменной длины, выражение оценивается и размер массива, который он оценивает, вычисляется во время выполнения.

Это означает: если тип выражения является типом VLA, тогда вычисляется выражение. Например:

#include <stdio.h>

int main() {
    int i = 0;
    int a[i];
    printf("%zu\n",sizeof(a[i++]));
    printf("%d\n",i); // Here, print 0 instead of 1
    return 0;
}

Итак, согласно ссылке, здесь i становлюсь 1. Но, с моим компилятором GCC, i печатаю как 0.

См. Демо-версию Wandbox.

Ответы

Ответ 1

Прежде всего, обратите внимание, что массив не может иметь нулевой размер, будь то VLA или нет. Таким образом, ваш код вызывает неопределенное поведение.

C11 6.7.6.2/5

"Если размер является выражением, которое не является целочисленным постоянным выражением:" / -/"... каждый раз, когда оно оценивается, оно должно иметь значение больше нуля".


Что касается реальной проблемы, a[i++] имеет тип int, а не тип VLA.

Чтобы получить побочный эффект, вы должны задействовать сам тип массива VLA, например sizeof(a). Только тогда операнд оценивается по побочным эффектам. Один пример, чтобы проиллюстрировать это:

#include <stdio.h>

int main() {
    int i=1, j=1;
    int a[i][j];
    int b[1][1];

    (void) sizeof(a[--i]);
    (void) sizeof(b[--j]);
    printf("%d %d", i, j);

    return 0;
}

Здесь i заканчивается как 0, так как первый sizeof оценивается из-за VLA, но j остается 1, потому что --j был частью sizeof для регулярного массива.

Ответ 2

Выражение в sizeof в вашем примере - int, а не vla. Если бы это было vla, все бы работало:

#include <stdio.h>

int main() {
    int i = 5;
    int a[i][i];
    printf("%zu\n",sizeof(a[--i]));
    printf("%d\n",i); // Here, print 4
    return 0;
}

Ответ 3

Из стандартов С# 6.5.3.4p2 [акцент мой]

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

В выражении:

sizeof(a[i++])

a[i++] не является VLA, а выражением оператора a[i++] индекса, приводящим к целому числу. Таким образом, операнд не оценивается и по той же причине компилятор предупреждает об этом утверждении:

warning: expression with side effects has no effect in an unevaluated context

Ответ 4

Чтобы взять слово клона нормативных ссылок на него:

6.5.3.4 - Операторы sizeof и _Alignof

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

Это будет оценено, если вы исправите свой пример для создания выражения с типом VLA, одним из таких способов

#include <stdio.h>

int main() {
    int i = 1;
    int a[5][i];
    printf("%zu\n",sizeof(a[i++]));
    printf("%d\n",i);
    return 0;
}

Распечатывает 2 в последней строке, так как i увеличивается.