Вопрос по c – Как sizeof (массив) работает во время выполнения?

23

Я читал, что оператор sizeof в C интерпретируется во время компиляции, и поскольку во время компиляции компилятор знает размер массива и его тип, sizeof способен вычислить количество байтов, занимаемых массивом. Но как sizeof работает для следующего кода:

<code> #include<stdio.h>
 #include<string.h>
 int main()
 {
    int n;
    scanf("%d",&n);
    int a[n];
    int s=sizeof(a);
    printf("%d",s);
    return 0;
 }
</code>

Здесь размер массива не известен во время компиляции, тогда как он работает правильно?

Массивы переменной длины являются исключением, для нихsizeof оценивается во время выполнения, а не во время компиляции. Daniel Fischer
@ M & # x414; & # x393; & # x393; & # x411; & # x414; LL: Ваш возможный дубликат имеет дело с другой ситуацией (malloc(), а не VLA, массив переменной длины). Jonathan Leffler
возможный дубликатUsing sizeof with a dynamically allocated array Matt Ball
@ M & # x414; & # x393; & # x393; & # x411; & # x414; LL Нет, речь идет оmallocВещи, а не о VLA. Daniel Fischer

Ваш Ответ

6   ответов
27

sizeof всегда вычисляется во время компиляции в C89. Поскольку C99 и массивы переменной длины, он вычисляется во время выполнения, когда массив переменной длины является частью выражения вsizeof операнд.

То же самое для оценкиsizeof операнд: он не оценивается в C89, но в C99, если операнд имеет тип массива переменной длины, он оценивается. Например:

int n = 5;
sizeof (int [n++]); 

// n is now 6
@ouah: с тех пор мы уже изучали, что выражение внутри оператора sizeof действительно не оценивается. то есть. sizeof (n ++) оставит n до 5 (если изначально n = 5). тогда почему значение n здесь меняется?
Спасибо, получил это сейчас. dark_shadow
Операнд типа массива переменной длины @rforritz является исключением из этого правила, в этом случае операнд вычисляется
@Маскаint [N] это имя типа C. Это массивN изint, когдаN не является константой, как в ответе, этоvariable length array.
Что это значит?int [n++]? Впервые вижу это на языке Си
1

sizeof вычисляется во время компиляции или во время выполнения (или, если говорить более формально, является ли его результат целочисленным константным выражением), результатsizeof основывается исключительно наtype of its argument а не какие-либо скрытые данные, сопровождающие сам массив переменной длины. Конечно когдаsizeof применяется к переменно-измененному типу, сгенерированная программа должна где-то отслеживать этот размер. Но он может просто пересчитать его, если выражение было достаточно простым, и переменные, из которых оно изначально получило длину, не могли измениться. Или, он может хранить размер типа где-то (по существу, в скрытой локальной переменной), но это не будет связано с объектом VLA каким-либо наблюдаемым способом (например, если вы передаете указатель на первый элемент VLA для другой функции этот указатель не может быть использован для восстановления длины VLA).

7

6.5.3.4

sizeof Оператор возвращает размер (в байтах) своего операнда, который может быть выражение или заключенное в скобки имя типа. Размер определяется по типу операнд. Результатом является целое число.If the type of the operand is a variable length array type, the operand is evaluated; в противном случае, операнд не оценивается, а результат целочисленная константа.

2

sizeof() оценивается во время выполнения. Компилятор, потому что он знает, что размерa основан на значенииn во время объявления массива генерирует код для использования соответствующего значенияn вернуть разумное значение дляsizeof().

В C99 не все виды использованияsizeof() может быть полностью оценена во время компиляции и сведена к постоянной времени выполнения.

@greg no, это VLA
Это правильно, я подправлю свой ответ.
doh Я не могу поверить, что набрал "compile" когда я имел в виду «запустить». Слишком рано утром. :)
Обратите внимание, что компилятор может использовать старое значение дляn; напримерint n = 5; char a[n]; n = 10; return sizeof(a); всегда возвращает 5, а не 10.
@DavidHeffernan: Я понимаю, надеюсь, мой обновленный ответ более ясен.
14

sizeof для массива переменной длины, размер которого не полностью известен во время компиляции, компилятор должен сгенерировать код, чтобы выполнить его часть во время выполнения.

Оптимизаторы высокого уровня gcc 4.6.3 преобразуют код, который вы показали в

scanf ("%d", &n);
t12 = (long unsigned int) n;
t13 = t12 * 4;
__builtin_alloca (t13);
t16 = (unsigned int) t12;
t17 = t16 * 4;
s18 = (int) t17;
printf ("%d", s18);

Это объясняет, что происходит под капотом? (Не откладывайте на глупое количество временных переменных - это артефакт программы, находящейся встатическое одиночное назначение Форма в точке, где я попросил дамп промежуточного кода.)

@TheMask ... Я должен также указать вам наinternals manual for GCC который объясняет, что такое промежуточные представления и как они работают.
Спасибо вам большое! Я проверяю все это. :)
@TheMask (продолжение) «Дерево» дампы обычно более полезны, чем "rtl" дампы, если только вы не пытаетесь отладить один из бэк-эндов GCC; (генерация кода для конкретной архитектуры). Вы можете ограничить вывод определенным проходом интереса, сказав-fdump-(tree|rtl)-PASSNAME вместо-allгде PASSNAME - это слово после числа в имени файла дампа. Увидетьgcc.gnu.org/onlinedocs/gcc-4.8.1/gcc/… (прокрутите немного вверх, затем прочитайте оттуда до конца документа) для получения дополнительной информации.
Поместите файл, который вы хотите скомпилировать, в отдельную директорию, затем вызовите gcc для него из оболочки в этой директории, добавив-fdump-tree-all к параметрам командной строки (вы, вероятно, хотите-S а также-O2 также). Вам нужно изолировать файл в чистом каталоге, потому что это создаст приблизительно 100 файлов промежуточного кода (и это только первая половина конвейера оптимизации;-fdump-rtl-all даст вам еще 60иш файлов). Затем вы можете прочитать их последовательно (они пронумерованы)
Как вы сгенерировали этот промежуточный код с помощью gcc?
2

sizeof определяется во время компиляции во всех случаях, кроме VLA. Для VLA,sizeof оценивается во время выполнения.

Похожие вопросы