Перейти к содержимому

Sizeof c что это

  • автор:

C/C++ Array Size

In C programming, arrays are used to store objects of the same type. Unlike the STL container std::vector in C++, determining the number of bytes for C arrays and the number of elements in C arrays are not straightforward.

In this blog post, I would like to discuss some of the concepts behind C arrays and how to determine the size of C arrays if it is possible.

Create Arrays

There are two types of arrays. The size of one type of the arrays would need to be known at compile-time, and the size of the other type of the arrays could be known at runtime. The former array would be created on the stack, and the latter array would be created on the heap.

To compile the program, please run the following command in the terminal.

C/C++ sizeof Operator

In C/C++, sizeof is used to determine the size of a variable or a type. Although the sizeof expressions, such as sizeof(variable) and sizeof(type) , could be used with parentheses, sizeof is a compile-time operator instead of a function in C/C++. This means that the compiler knows the exact value of sizeof(variable) and sizeof(type) at compile time.

Determine Array Size

The correct way of determining the size of arrays on the stack has been presented as follows. The size of arrays on the heap could not be determined.

To compile the program, please run the following command in the terminal.

I got the following outputs from the program. Some of the values might be different depending on the computers.

The questions is why sizeof(arr1) and sizeof(ptrArr1) result in different values. The compiler knows arr1 is neither a variable of integer nor a pointer of int, but an integer array of size 10. Therefore, sizeof(arr1) is returning the number of bytes for the array arr1 . It is some of the few cases where the array type does not decay to a pointer type. ptrArr1 , however, is just a normal pointer decayed from integer array type. Therefore, sizeof(ptrArr1) is returning the number of bytes for a single pointer ptrArr1 .

What are the differences between malloc and new?

Obviously, one major difference is that malloc does not call constructor since it does not have to know the type of variables we want to write to the memory, while new has to call a constructor.

How does delete and free know the size of an array?

It is a little bit weird that we could not determine the size of an array on the heap, but free and delete[] knows the number of bytes for the array so that they could recycle the memory accordingly. The answer is it really depends on the implementation.

There is a good diagram on the StackOverflow which I borrowed. It is a good implementation for the arrays on the heap.

free and delete[] could always look at the headers on the memory before the pointer and determine the size of the array, because free and delete[] assume all the pointers given to them are pointers pointing to the memories on the heap. sizeof , however, has no such assumptions. In addition, as mentioned above sizeof is a compile-time operator and it could not look at the potential header at runtime.

What does sizeof do?

What do sizeof (k) or sizeof (int) and sizeof (char) mean?

Peter Mortensen's user avatar

4 Answers 4

sizeof(x) returns the amount of memory (in bytes) that the variable or type x occupies. It has nothing to do with the value of the variable.

For example, if you have an array of some arbitrary type T then the distance between elements of that array is exactly sizeof(T) .

When used on a variable, it is equivalent to using it on the type of that variable:

As a rule-of-thumb, it is best to use the variable name where possible, just in case the type changes:

When used on user-defined types, sizeof still returns the amount of memory used by instances of that type, but it’s worth pointing out that this does not necessary equal the sum of its members.

While sizeof(int) + sizeof(char) is typically 5 , on many machines, sizeof(Foo) may be 8 because the compiler needs to pad out the structure so that it lies on 4 byte boundaries. This is not always the case, and it’s quite possible that on your machine sizeof(Foo) will be 5, but you can’t depend on it.

4.3 – Размеры объектов и оператор sizeof

Как вы узнали из урока «4.1 – Введение в основные типы данных», память на современных машинах обычно организована в блоки размером с байты, причем каждый байт памяти имеет уникальный адрес. До этого момента было полезно думать о памяти как о связке почтовых ящиков, куда мы можем помещать и извлекать информацию, а переменные в этой аналогии – имена для доступа к этим почтовым ящикам.

Однако эта аналогия не совсем верна в одном отношении – большинство объектов на самом деле занимают более 1 байта памяти. Один объект может использовать 2, 4, 8 или более последовательных адресов памяти. Объем памяти, который использует объект, зависит от его типа данных.

Поскольку мы обычно обращаемся к памяти через имена переменных (а не напрямую через адреса памяти), компилятор может скрыть от нас детали того, сколько байтов использует какой-либо конкретный объект. Когда мы обращаемся к некоторой переменной x , компилятор знает, сколько байтов данных нужно получить (в зависимости от типа переменной x ), и может справиться с этой задачей за нас.

Тем не менее, есть несколько причин, по которым полезно знать, сколько памяти использует какой-либо объект.

Во-первых, чем больше памяти использует объект, тем больше информации он может вместить.

Один бит может содержать 2 возможных значения, 0 или 1:

бит 0
0
1

2 бита могут содержать 4 возможных значения:

бит 0 бит 1
0 0
0 1
1 0
1 1

3 бита могут содержать 8 возможных значений:

бит 0 бит 1 бит 2
0 0 0
0 0 1
0 1 0
0 1 1
1 0 0
1 0 1
1 1 0
1 1 1

В общем, объект из n битов (где n – целое число) может содержать 2 n (2 в степени n, также иногда записывается 2^n) уникальных значений. Следовательно, при байте из 8 битов, объект размером 1 байт может принимать 2 8 (256) различных значений. Объект, который использует 2 байта, может принимать 2^16 (65536) разных значений!

Таким образом, размер объекта ограничивает количество уникальных значений, которые он может принимать – объекты, которые используют больше байтов, могут принимать большее количество уникальных значений. Мы рассмотрим это дальше, когда поговорим подробнее о целых числах.

Во-вторых, у компьютеров объем свободной памяти ограничен. Каждый раз, когда мы определяем объект, небольшая часть этой свободной памяти используется, пока существует объект. Поскольку у современных компьютеров много памяти, это влияние обычно незначительно. Однако для программ, которым требуется большое количество объектов или данных (например, игра, которая отображает миллионы полигонов), разница между использованием 1- и 8-байтовых объектов может быть значительной.

Ключевой момент

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

Размеры основных типов данных

Следующий очевидный вопрос – «сколько памяти занимают переменные разных типов данных?». Вы можете быть удивлены, обнаружив, что размер конкретного типа данных зависит от компилятора и/или архитектуры компьютера!

C++ гарантирует только минимальный размер каждого базового типа данных:

Категория Тип Минимальный размер Примечание
логический bool 1 байт
символ char 1 байт всегда точно 1 байт
wchar_t 1 байт
char16_t 2 байта тип C++11
char32_t 4 байта тип C++11
целочисленное значение short 2 байта
int 2 байта
long 4 байта
long long 8 байт тип C99/C++11
с плавающей запятой float 4 байта
double 8 байт
long double 8 байт

Однако фактический размер переменных на вашем компьютере может быть другим (особенно int , который чаще всего составляет 4 байта).

Лучшая практика

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

Объекты базовых типов данных обычно работают очень быстро.

Оператор sizeof

Чтобы определить размеры типов данных на конкретной машине, C++ предоставляет оператор с именем sizeof . Оператор sizeof – это унарный оператор, который принимает тип или переменную и возвращает ее размер в байтах. Вы можете скомпилировать и запустить следующую программу, чтобы узнать размеры некоторых из ваших типов данных:

Вот результат работы этой программы, полученный автором, на машине x64 при использовании Visual Studio:

Ваши результаты могут отличаться, если вы используете другой тип машины или другой компилятор. Обратите внимание, что вы не можете использовать оператор sizeof для типа void , поскольку он не имеет размера (это приведет к ошибке компиляции).

Для продвинутых читателей

Если вам интересно, что такое " \t " в приведенной выше программе, это специальный символ, который вставляет табуляцию (в этом примере мы используем ее для выравнивания выходных столбцов). Мы рассмотрим " \t " и другие специальные символы в уроке «4.11 – Символы».

Вы также можете использовать оператор sizeof для имени переменной:

Производительность при использовании базовых типов данных

На современных машинах объекты базовых типов данных работают быстро, поэтому производительность при использовании этих типов обычно не должна быть проблемой.

В качестве отступления.

Вы можете предположить, что типы, которые используют меньше памяти, будут быстрее, чем типы, которые используют больше памяти. Это не всегда так. Процессоры часто оптимизированы для обработки данных определенного размера (например, 32 бита), и типы, соответствующие этому размеру, могут обрабатываться быстрее. На такой машине 32-битный int может быть быстрее, чем 16-битный short или 8-битный char .

sizeof operator

Depending on the computer architecture, a byte may consist of 8 or more bits, the exact number provided as CHAR_BIT .

sizeof ( char ) , sizeof ( signed char ) , and sizeof ( unsigned char ) always return 1 .

sizeof cannot be used with function types, incomplete types (including void ), or bit-field lvalues.

When applied to an operand that has structure or union type, the result is the total number of bytes in such an object, including internal and trailing padding. The trailing padding is such that if the object were an element of an array, the alignment requirement of the next element of this array would be satisfied, in other words, sizeof ( T ) returns the size of an element of a T [ ] array.

If type is a VLA type and changing the value of its size expression would not affect the result of sizeof , it is unspecified whether or not the size expression is evaluated.

Except if the type of expression is a VLA, (since C99) expression is not evaluated and the sizeof operator may be used in an integer constant expression.

If the type of expression is a variable-length array type, expression is evaluated and the size of the array it evaluates to is calculated at run time.

Number of elements in any array a including VLA (since C99) may be determined with the expression sizeof a / sizeof a [ 0 ] . Note that if a has pointer type (such as after array-to-pointer conversion of function parameter type adjustment), this expression would simply divide the number of bytes in a pointer type by the number of bytes in the pointed type.

[edit] Keywords

[edit] Example

Sample output corresponds to a platform with 64-bit pointers and 32-bit int

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *

Школа онлайн с государственным аттестатом