Оператор 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
увеличивается.