Как sizeof знает размер массива операндов?

Это может быть глупым вопросом, но как оператор sizeof знает размер операнда массива, если вы не передаете количество элементов в массиве. Я знаю, что он не возвращает общее количество элементов в массиве, но размер в байтах, но чтобы понять это, ему все равно нужно знать, когда заканчивается массив. Просто любопытно, как это работает.

31
задан marchinram 26 August 2010 в 20:48
поделиться

12 ответов

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

45
ответ дан 27 November 2019 в 21:26
поделиться

За исключением одного случая, sizeof делает свое дело во время компиляции. Во время компиляции компилятор отслеживает полный тип объекта. t включает размер, попытка использовать sizeof потерпит неудачу], а sizeof в основном просто «экспортирует» одну часть этой информации из компилятора в компилируемый код, поэтому она становится по существу константа в результирующем коде.

Исключение составляет случай, когда sizeof применяется к массиву переменной длины (VLA)1. Применительно к VLA функция sizeof оценивает свой операнд (чего не делает иначе) и выдает фактический размер VLA. В этом случае результат не является постоянным.


1. VLA официально стали частью C в C99, но некоторые компиляторы поддерживали их до этого. Хотя официально это не является частью C++, некоторые компиляторы (например, g++) также включают VLA в качестве расширения C++.

14
ответ дан 27 November 2019 в 21:26
поделиться

Компилятор знает размер каждого типа в вашем приложении и sizeof просто просит компилятор произвести это значение для вас.

10
ответ дан 27 November 2019 в 21:26
поделиться

Sizeof можно применять только к полностью определенным типам. Компилятор либо сможет определить размер во время компиляции (т.например, если у вас было объявление типа int foo[8];), или он сможет определить, что ему нужно добавить код для отслеживания размера массива переменной длины (например, если у вас есть объявление типа int foo[n+3];).

В отличие от других ответов здесь, обратите внимание, что начиная с C99, sizeof()не обязательно определяется во время компиляции, поскольку массивы могут иметь переменную длину.

5
ответ дан 27 November 2019 в 21:26
поделиться

Цитата из вики:

Это ответственность автор компилятора для реализации оператор sizeof определенным образом и правильно для данной реализации язык. Оператор sizeof должны учитывать реализация основных схема распределения памяти для получения размеры различных типов данных. размер обычно оператор времени компиляции, который означает, что во время компиляции sizeof и его операнд заменяется на результат-значение. Это очевидно в код на языке ассемблера, созданный C или компилятор С++. По этой причине, sizeof квалифицируется как оператор, даже хотя его использование иногда выглядит как вызов функции.

2
ответ дан 27 November 2019 в 21:26
поделиться

Оператор sizeof «знает» размер всех атомарных типов данных, поскольку структуры, объединения и массивы могут быть только построенный путем сборки атомарных типов, легко определить размер массива любого типа. Он использует базовую арифметику для определения сложных типов (во время компиляции).

2
ответ дан 27 November 2019 в 21:26
поделиться

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

char * array;
int size;
//Get size somehow.
array = malloc(size*(sizeof(char)));

// теперь при компиляции компилятор точно знает размер char. так как он должен выровнять их в памяти. В этот момент ОС знает, какой размер она должна выделить.

Массивы переменной длины, с другой стороны, создаются в стеке. Но любая память, выделенная malloc, будет создана в куче.

1
ответ дан 27 November 2019 в 21:26
поделиться

Sizeof — оператор времени компиляции; у него столько же информации, сколько и у компилятора. (И очевидно, что компилятор действительно знает размер массива).

Вот почему, если вы вызываете sizeof для указателя, вы получаете ширину указателя, а не размер массива, на который указывает этот указатель.

9
ответ дан 27 November 2019 в 21:26
поделиться

Если вы используете sizeof для локальной переменной, она знает, сколько элементов вы объявили. Если вы используете sizeof для параметра функции, он не знает; он обрабатывает параметр как указатель на массив, а sizeof дает размер указателя.

3
ответ дан 27 November 2019 в 21:26
поделиться

Проблема, лежащая в основе вашей проблемы с пониманием этого, может заключаться в том, что вы путаете массивы и указатели, как это делают многие. Однако массивы не являются указателями. double da[10] — это массив из десяти double, а не double*, и это наверняка известно компилятору, когда вы просите его оценить sizeof(da). Вас не удивит, что компилятор знает sizeof(double)?

Проблема с массивами заключается в том, что они автоматически распадаются на указатели на свои первые элементы во многих контекстах (например, когда они передаются в функции ). Но тем не менее массив — это массив, а указатели — это указатели.

23
ответ дан 27 November 2019 в 21:26
поделиться

sizeof обычно оценивается во время компиляции. Заметным исключением являются массивы переменной длины C99.

int main(int argc, char **argv)
{
    if (argc > 1)
    {
        int count = atoi(argv[1]);
        int someArray[count];

        printf("The size is %zu bytes\n", sizeof someArray);
    }
    else puts("No");
}
2
ответ дан 27 November 2019 в 21:26
поделиться

Sizeof всегда оценивается во время компиляции. В многопроходном компиляторе при создании таблицы символов компилятор должен определить размер каждого объявленного символа, чтобы продолжить генерацию промежуточного кода. Таким образом, для всех ссылок sizeof в коде заменяется точное значение. На этапе генерации промежуточного кода все операторы, операторы преобразуются в правильный промежуточный код (ASM/другой формат). Наконец, на этапе генерации кода m/c он преобразует его в машинный код.

Некоторые рассуждения, приведенные выше, относительно динамических распределений, связанных с sizeof, вообще не относятся к контексту. Любая ссылка на size(*p), где p является указателем любого типа данных, компилятор просто определяет тип данных *p и заменяет его размер, а не проверяет заголовок MCB выделенного блока, чтобы увидеть, что выделено объем памяти. Это не во время выполнения. Например, двойное *p; sizeof(*p) по-прежнему можно выполнять без выделения памяти для указателя p. Как это возможно?

1
ответ дан 27 November 2019 в 21:26
поделиться