Оператор 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.


person msc    schedule 07.02.2018    source источник
comment
a[i++] не является выражением типа VLA. В конечном счете, это индексное выражение, имеющее тип int. Кроме того, даже для VLA a[0] является нарушением ограничений.   -  person StoryTeller - Unslander Monica    schedule 07.02.2018
comment
Длина VLA определяется во время ее определения. В приведенном выше коде длина будет равна 0, поэтому в VLA не будет элементов. Размер не меняется после того, как он был определен. Кроме того, длина должна быть больше нуля, иначе это будет неопределенное поведение.   -  person Ian Abbott    schedule 07.02.2018
comment
Я не знал, что у C есть VLA. Я узнал что-то новое, если только OP не пометил C вместо C ++.   -  person byxor    schedule 07.02.2018
comment
@byxor - это C ++, который не имеет их, кроме расширений компилятора (потому что указанные компиляторы также поддерживают C).   -  person StoryTeller - Unslander Monica    schedule 07.02.2018
comment
попробуйте int a[i][i]; sizeof(a[i++]), это будет sizeof(vla)   -  person Uprooted    schedule 07.02.2018
comment
Возможный дубликат Почему sizeof(x++) не увеличивает x?   -  person Maquefel    schedule 07.02.2018
comment
речь идет о sizeof+vla, это не дубликат этого вопроса   -  person Uprooted    schedule 07.02.2018


Ответы (4)


Прежде всего, обратите внимание, что массив не может иметь нулевой размер, будь то 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 для обычного массива.

person Lundin    schedule 07.02.2018
comment
Не по теме исходного вопроса, но есть идеи, почему в стандарте предусмотрен особый случай для выражений типа VLA? - person Ajay Brahmakshatriya; 07.02.2018
comment
@Ajay Предполагая int a[i];, выражение sizeof a должно иметь возможность вычислять правильный результат во время выполнения, поскольку значение i неизвестно во время компиляции. - person user694733; 07.02.2018
comment
@AjayBrahmakshatriya Поскольку размер устанавливается только во время выполнения, поэтому он не обязательно может быть предварительно рассчитан во время компиляции. - person Lundin; 07.02.2018

Выражение в 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;
}
person Uprooted    schedule 07.02.2018

Из C Standards#6.5.3.4p2 [< em>выделено мной]

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

В выражении:

sizeof(a[i++])

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

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

person H.S.    schedule 07.02.2018