4.9. Оператор sizeof

Оператор sizeof возвращает размер в байтах результата выражения или указанного по имени типа. Оператор имеет правосторонний порядок. Результат оператора sizeof — это константное выражение (см. раздел 2.4.4) типа size_t (см. раздел 3.5.2). Оператор существует в двух формах.

sizeof(тип)

sizeof выражение

Во второй форме оператор sizeof возвращает размер типа, возвращаемого выражением. Оператор sizeof необычен тем, что он не выполняет свой операнд.

Sales_data data, *p;

sizeof(Sales_data);  // размер, необходимый для хранения объекта

                     // типа Sales_item

sizeof data;         // размер типа данных, аналог sizeof(Sales_data)

sizeof p;            // размер указателя

sizeof *p;           // размер типа, на который указывает указатель p,

                     // т.е. sizeof(Sales_data)

sizeof data.revenue; // размер типа члена revenue класса Sales_data

sizeof Sales_data::revenue; // альтернативный способ получения

                            // размера revenue

Наиболее интересен пример sizeof *p. Во-первых, поскольку оператор sizeof имеет правосторонний порядок и тот же приоритет, что и оператор *, это выражение группируется справа налево. Таким образом, оно эквивалентно выражению sizeof(*p). Во-вторых, поскольку оператор sizeof не выполняет свой операнд, не имеет значения, допустим ли указатель p (т.е. инициализирован ли он) (см. раздел 2.3.2). Обращения к значению недопустимого указателя оператор sizeof не осуществляет, и указатель фактически не используется, поэтому он безопасен. Ему и не нужно обращаться к значению указателя, чтобы выяснить, какой тип он возвратит.

По новому стандарту для доступа к члену класса при получении его размера можно использовать оператор области видимости. Обычно к членам класса можно обратиться только через объект этого класса. Больше не обязательно предоставлять объект, так как оператор sizeof не обязан выбирать член класса, чтобы узнать его размер.

Результат применения оператора sizeof частично зависит от типа, к которому он применен.

• Если это тип char или выражения, результат которого имеет тип char, то это гарантированно будет 1.

• Если это ссылка, то возвращает размер типа объекта, на который она ссылается.

• Если это указатель, то возвращается размер, необходимый для хранения указателя.

• Если это обращение к значению указателя, то возвращается размер типа объекта, на который он указывает, вне зависимости от его допустимости.

• Если это массив, то возвращается размер всего массива. Это эквивалентно получению размера элемента массива и его умножению на количество элементов. Обратите внимание, что оператор sizeof не преобразует массив в указатель.

• Если это строка или вектор, то возвращается размер только фиксированной части этих типов; но не размер, используемый элементами объекта.

Поскольку оператор sizeof возвращает размер всего массива, разделив размер массива на размер элемента, можно определить количество элементов в массиве:

// sizeof(ia)/sizeof(*ia) возвращает количество элементов в ia

constexpr size_t sz = sizeof (ia)/sizeof(*ia);

int arr2[sz]; // ok: sizeof возвращает константное выражение

              // (p. 2.4.4)

Так как оператор sizeof возвращает константное выражение, его результат можно использовать в выражении для определения размерности массива.

Упражнения раздела 4.9

Упражнение 4.28. Напишите программу для вывода размера каждого из встроенных типов.

Упражнение 4.29. Предскажите вывод следующего кода и объясните свое рассуждение. Напишите и выполните соответствующую программу. Совпадает ли вывод с ожиданиями? Если нет, то объясните почему.

int x[10]; int *p = x;

cout << sizeof(x)/sizeof(*x) << endl;

cout << sizeof(p)/sizeof(*p) << endl;

Упражнение 4.30. Используя таблицу из раздела 4.12, расставьте скобки в следующих выражениях так, чтобы продемонстрировать порядок его обработки:

(a) sizeof x + y  (b) sizeof p->mem[i]

(с) sizeof а < b  (d) sizeof f()