2010-08-26 2 views
25

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

+0

См: http://stackoverflow.com/questions/492384/how-to-find-the-sizeof-a-pointer-pointing-to-an-array – 2010-08-26 20:52:39

+6

+1 ко всем тем, кто говорит, ' sizeof' был оператором времени компиляции, -1 всем, кто сказал, что он отслеживает размер массива, указатель указывает на время выполнения. –

+0

Ничего себе! десять ответов, пока я не закончил свой ответ. Я старею ;-) – stacker

ответ

39

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

+0

уверен, что это неправда, за обсуждение самого вопроса, а также чтение спецификации - по крайней мере, для современных C. Было бы лучше, если бы этот ответ был удален. Http: //en.wikipedia.org/wiki/Sizeof – xaxxon

+2

@xaxxon: стандарт не * явно * говорит, что он оценивается во время компиляции, но он говорит, что 'sizeof' не оценивает его операнд. Выражение операнда имеет смысл только для компилятора, так что это действительно единственное место, которое можно реализовать. VLA обрабатываются косвенно компилятором. Компилятор уже должен сгенерировать код, чтобы вычислить, сколько места выделяется для VLA (размер элемента массива * какая-то переменная), поэтому он может повторно использовать этот номер для любых вызовов 'sizeof' на этом VLA. – bta

9

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

+0

Это неправда. переменная длина массива sizeof вызовов не обрабатывается во время компиляции. Вы должны обновить свой ответ или удалить его. http://en.wikipedia.org/wiki/Sizeof – xaxxon

+0

@xaxxon: На данный момент массивы переменной длины недействительны в C++, поэтому ответ стоит: размер * всех допустимых типов C++ * вычисляется во время компиляции. Массивы переменной длины для C++ были предложены комитету на последнем собрании, и предложение было хорошо воспринято, но это будет недействительным C++ до тех пор, пока не будет одобрен следующий стандарт (C++ 14). Даже с VLA, компилятор * знает * размер (он знает выражение, из которого был создан массив, поэтому он может сохранить номер в стороне), поскольку VLA не могут масштабировать область действия, которую компилятор может вводить тем же значением, где это необходим. –

8

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

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

+0

Итак, (не используя C++ в течение нескольких лет), что произойдет, если вы попросите sizeof и разыщите указатель на массив? Делает ли sizeof просто сбой, или он ищет что-то, что он записал о размере массива и возвращает его? –

+2

Если вы разыщите указатель, вы получите ссылку на объект, который хранится в массиве, и sizeof вернет его. 'int a [5]; int * p = a; assert (sizeof (* p) == sizeof (int); ' –

+0

Это неверно: размер переменной size sizeof вызовов не обрабатывается во время компиляции. Вы должны обновить свой ответ или удалить его. http: //en.wikipedia. org/wiki/Sizeof – xaxxon

2

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

+0

Он делает знать. Параметр * является * указателем (к первому элементу, а не к массиву), а компилятор знает размер указателя. C не имеет параметров массива. –

12

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

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


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

+3

Компилятор отслеживает полный тип ... если только это не так, потому что тип является неполным. В этом случае 'sizeof' не может быть использован. – Potatoswatter

+0

@Potatoswatter: хорошая точка. Изменено, чтобы отразить этот факт. –

+0

Это неправда. переменная длина массива sizeof вызовов не обрабатывается во время компиляции. Вы должны обновить свой ответ или удалить его. http://en.wikipedia.org/wiki/Sizeof – xaxxon

1

Цитата wiki:

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

+2

Хотя это верно, на самом деле он не отвечает на вопрос OP. –

1

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

4

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

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

+0

s/время выполнения/время компиляции/g, и это станет хорошим ответом. – ninjalj

+0

Derp. Благодарю. :-) – ngroot

+0

Разговор о самоисполняющихся пророчествах :) – ninjalj

19

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

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

+2

+1 для объяснения корня общего недоразумения здесь. –

+0

Абсолютно верно, sbi. Главы 4, 9 и 10 из выдающейся книги Питера ван дер Линдена «Программирование программистов на языке С» делают большую работу по разграничению указателей и массивов. Ад, глава 4 называется «Шокирующая правда: C Массивы и указатели не то же самое», как сказал sbi. И он посвящает 15 страниц этой теме. Ознакомьтесь с оглавлением, например. Глава 4, 9 и 10: http://books.google.com/books?id=9t5uxP9xHpwC&lpg=PP1&dq=expert%20c%20programming&pg=PR8#v=onepage&q&f=false – Dan

0

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

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

// теперь во время компиляции компилятор точно знает размер символа. так как он должен выровнять их по памяти. На данный момент OS знает, сколько размера он должен выделить.

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

0

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

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

+0

«Размер всегда оценивается во время компиляции». Это неверно для массивов переменной длины, как описано в других ответах и ​​комментариях. Этот ответ должен быть удален и не подходит для текущего языка C (см. Спецификацию). http://en.wikipedia.org/wiki/Sizeof – xaxxon

1

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"); 
}