Является ли поведение sizeof (* ptr) undefined при указании на недопустимую память?

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

Но какое правило при использовании в выражении передается sizeof?

Например:

int* ptr = 0;
int size = sizeof(*ptr);

Это также undefined?

Ответ 1

В большинстве случаев (по крайней мере на C) вы обнаружите, что sizeof(*x) вообще не оценивает *x. Стандарт C99 имеет это, например, в 6.5.3.4 The sizeof operator, part /2 (my bolding):

Оператор sizeof дает размер (в байтах) своего операнда, который может быть выражением или заключенным в скобки именем типа. Размер определяется из типа операнда. Результат - целое число. Если тип операнда - тип массива переменной длины, то операнд оценивается; в противном случае операнд не оценивается, а результат представляет собой целочисленную константу.

Итак, для всех не-VLA разыменование не происходит. Если тип *x является VLA, который рассмотрел фазу исполнения sizeof, то, что нужно проработать во время работы кода, - все остальные могут быть вычислены во время компиляции.

С++ имеет несколько разные правила, как показано в 5.3.3. Sizeof, part /1:

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

5. Expressions определяет термин "неоцененный операнд" в части /8:

В некоторых контекстах отображаются неоцененные операнды. Неопределенный операнд не оценивается.

(возможно, одна из самых бесполезных избыточных фраз, которые я читал на некоторое время, но я не знаю, что происходит с сознанием людей ИСО, когда они написали ее).

Ответ 2

Нет. sizeof является оператором и работает над типами, а не с фактическим значением (которое не оценивается).

Чтобы напомнить вам, что это оператор, я предлагаю вам привыкнуть к отсутствию скобок там, где это возможно.

int* ptr = 0;
size_t size = sizeof *ptr;
size = sizeof (int);   /* brackets still required when naming a type */

Ответ 3

Ответ может быть различным для C, где sizeof не обязательно является конструкцией времени компиляции, но в С++ выражение, предоставляемое sizeof, никогда не оценивается. Таким образом, никогда не будет возможности для поведения undefined. По аналогичной логике вы также можете "вызывать" функции, которые никогда не определены [поскольку функция никогда не вызывается, определение не требуется], факт, который часто используется в правилах SFINAE.

Ответ 4

sizeof (* ptr) в этом случае совпадает с sizeof (int).

Ответ 5

sizeof и decltype не оценивают свои операнды, только типы вычислений.