Какой из них создаст нулевого указателя?

В стандарте говорится, что разыменование нулевого указателя приводит к неопределенному поведению. Но каков "нулевой указатель"? В следующем коде, что мы называем "нулевым указателем":

struct X
{
  static X* get() { return reinterpret_cast<X*>(1); }
  void f() { }
};

int main()
{
  X* x = 0;
  (*x).f(); // the null pointer?  (1)

  x = X::get();
  (*x).f(); // the null pointer?  (2)

  x = reinterpret_cast<X*>( X::get() - X::get() );
  (*x).f(); // the null pointer?  (3)

  (*(X*)0).f(); // I think that this the only null pointer here (4)
}

Моя мысль - то, что разыменование нулевого указателя происходит только в последнем случае.Я прав? Есть ли различие между нулевыми указателями времени компиляции и временем выполнения согласно Стандарту C++?

14
задан Johannes Schaub - litb 24 May 2010 в 13:40
поделиться

4 ответа

Только первый и последний являются нулевыми указателями. Остальные являются результатами reinterpret_cast и, таким образом, оперируют значениями указателя, определенными реализацией. Независимо от того, является ли их поведение неопределенным, зависит от того, есть ли объект по адресу, на который вы выполняли приведение.

12
ответ дан 1 December 2019 в 08:52
поделиться

Целочисленное постоянное выражение, значение которого равно 0, допустимо как нулевой указатель, поэтому в первом случае также осуществляется разыменование нулевого указателя.

Указатель, установленный в 0 посредством арифметических вычислений, не обязательно является нулевым указателем. В большинстве реализаций он будет вести себя так же, как нулевой указатель, но это не гарантируется стандартом.

12
ответ дан 1 December 2019 в 08:52
поделиться

Стандарт C++ (2003) 4.10

4.10 Преобразования указателей

1 Константа нулевого указателя является интегральное константное выражение (5.19) rvalue целочисленного типа, которое оценивается в ноль. Константа нулевого указателя может быть быть преобразована к типу указателя; в результате результатом является значение нулевого указателя этого типа и отличимо от любого другого значения указателя на объект или указателя на тип функции. Два нулевых указателя одного и того же типа должны сравниваться одинаково. Преобразование константы нулевого указателя в указатель на cv-квалифицированного типа является единственным преобразование, а не последовательность преобразование указателя, за которым следует преобразование квалификации (4.4).

5.2.10 Переинтерпретировать приведение

Примечание 64) Преобразование интегрального константного выражения (5.19) со значением ноль всегда дает нулевой указатель (4.10), но преобразование других выражений которые случайно имеют нулевое значение, не обязательно не приводит к нулевому указателю.

1) X* x = 0; (*x).f(); Да. 0 является интегральным константным выражением и преобразуется в константу нулевого указателя. Затем константа нулевого указателя может быть преобразована в значение нулевого указателя.

2) x = X::get(); нет, см. примечание 64 в 5.2.10

3) x = reinterpret_cast( X::get() - X::get() ); нет, см. примечание 64 в 5.2.10

4) ((X)0).f(); Да. 0 (интегральное константное выражение) --> константа нулевого указателя --> значение нулевого указателя.

7
ответ дан 1 December 2019 в 08:52
поделиться
X* x = 0;
(*x).f(); // the null pointer?  (1)

Я думаю, что это квалифицируется как разыменование, хотя f () на самом деле никогда не использует указатель this , и в X нет виртуальных методов. Моим рефлексом было сказать, что это крушение, но теперь, когда я думаю об этом, я не так уверен.

x = X::get();
(*x).f(); // the null pointer?  (2)

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

x = reinterpret_cast<X*>( X::get() - X::get() );
(*x).f(); // the null pointer?  (3)

Компилируется ли выражение X :: get () - X :: get () ? Я не считал законным вычитание указателя из другого подобного указателя.

РЕДАКТИРОВАТЬ: Ооо! Конечно, это законно. О чем я только думал? Ясно, что я темно-бордовый.

0
ответ дан 1 December 2019 в 08:52
поделиться
Другие вопросы по тегам:

Похожие вопросы: