Это может быть глупым вопросом, но как оператор sizeof знает размер операнда массива, если вы не передаете количество элементов в массиве. Я знаю, что он не возвращает общее количество элементов в массиве, но размер в байтах, но чтобы понять это, ему все равно нужно знать, когда заканчивается массив. Просто любопытно, как это работает.
sizeof
интерпретируется во время компиляции, и компилятор знает, как был объявлен массив (и, следовательно, сколько места он занимает). Вызов sizeof
для динамически распределяемого массива, скорее всего, не сделает то, что вы хотите, потому что (как вы упомянули) конечная точка массива не указана.
За исключением одного случая, sizeof
делает свое дело во время компиляции. Во время компиляции компилятор отслеживает полный тип объекта. t включает размер, попытка использовать sizeof
потерпит неудачу], а sizeof
в основном просто «экспортирует» одну часть этой информации из компилятора в компилируемый код, поэтому она становится по существу константа в результирующем коде.
Исключение составляет случай, когда sizeof
применяется к массиву переменной длины (VLA)1. Применительно к VLA функция sizeof
оценивает свой операнд (чего не делает иначе) и выдает фактический размер VLA. В этом случае результат не является постоянным.
1. VLA официально стали частью C в C99, но некоторые компиляторы поддерживали их до этого. Хотя официально это не является частью C++, некоторые компиляторы (например, g++) также включают VLA в качестве расширения C++.
Компилятор знает размер каждого типа в вашем приложении и sizeof
просто просит компилятор произвести это значение для вас.
Sizeof можно применять только к полностью определенным типам. Компилятор либо сможет определить размер во время компиляции (т.например, если у вас было объявление типа int foo[8];), или он сможет определить, что ему нужно добавить код для отслеживания размера массива переменной длины (например, если у вас есть объявление типа int foo[n+3];).
В отличие от других ответов здесь, обратите внимание, что начиная с C99, sizeof()не обязательно определяется во время компиляции, поскольку массивы могут иметь переменную длину.
Цитата из вики:
Это ответственность автор компилятора для реализации оператор sizeof определенным образом и правильно для данной реализации язык. Оператор sizeof должны учитывать реализация основных схема распределения памяти для получения размеры различных типов данных. размер обычно оператор времени компиляции, который означает, что во время компиляции sizeof и его операнд заменяется на результат-значение. Это очевидно в код на языке ассемблера, созданный C или компилятор С++. По этой причине, sizeof квалифицируется как оператор, даже хотя его использование иногда выглядит как вызов функции.
Оператор sizeof «знает» размер всех атомарных типов данных, поскольку структуры, объединения и массивы могут быть только построенный путем сборки атомарных типов, легко определить размер массива любого типа. Он использует базовую арифметику для определения сложных типов (во время компиляции).
sizeof вычисляется во время компиляции. Вот почему, когда вы создаете динамический массив, вы создаете его следующим образом.
char * array;
int size;
//Get size somehow.
array = malloc(size*(sizeof(char)));
// теперь при компиляции компилятор точно знает размер char. так как он должен выровнять их в памяти. В этот момент ОС знает, какой размер она должна выделить.
Массивы переменной длины, с другой стороны, создаются в стеке. Но любая память, выделенная malloc, будет создана в куче.
Sizeof
— оператор времени компиляции; у него столько же информации, сколько и у компилятора. (И очевидно, что компилятор действительно знает размер массива).
Вот почему, если вы вызываете sizeof
для указателя, вы получаете ширину указателя, а не размер массива, на который указывает этот указатель.
Если вы используете sizeof
для локальной переменной, она знает, сколько элементов вы объявили. Если вы используете sizeof
для параметра функции, он не знает; он обрабатывает параметр как указатель на массив, а sizeof
дает размер указателя.
Проблема, лежащая в основе вашей проблемы с пониманием этого, может заключаться в том, что вы путаете массивы и указатели, как это делают многие. Однако массивы не являются указателями. double da[10]
— это массив из десяти double
, а не double*
, и это наверняка известно компилятору, когда вы просите его оценить sizeof(da)
. Вас не удивит, что компилятор знает sizeof(double)
?
Проблема с массивами заключается в том, что они автоматически распадаются на указатели на свои первые элементы во многих контекстах (например, когда они передаются в функции ). Но тем не менее массив — это массив, а указатели — это указатели.
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");
}
Sizeof всегда оценивается во время компиляции. В многопроходном компиляторе при создании таблицы символов компилятор должен определить размер каждого объявленного символа, чтобы продолжить генерацию промежуточного кода. Таким образом, для всех ссылок sizeof в коде заменяется точное значение. На этапе генерации промежуточного кода все операторы, операторы преобразуются в правильный промежуточный код (ASM/другой формат). Наконец, на этапе генерации кода m/c он преобразует его в машинный код.
Некоторые рассуждения, приведенные выше, относительно динамических распределений, связанных с sizeof, вообще не относятся к контексту. Любая ссылка на size(*p), где p является указателем любого типа данных, компилятор просто определяет тип данных *p и заменяет его размер, а не проверяет заголовок MCB выделенного блока, чтобы увидеть, что выделено объем памяти. Это не во время выполнения. Например, двойное *p; sizeof(*p) по-прежнему можно выполнять без выделения памяти для указателя p. Как это возможно?