TGViewer
C++: Хроники Дурки🚑 C++: Хроники Дурки🚑 @cpp_durka · 916 subscribers
Post #34 1.12K
Обычно когда спрашивают, что такое nullptr, получают в ответ, что это указатель равный нулю.

Более продвинутые говорят, что это зависит от имплементации, и приводят в пример какие-то embedded сценарии архитектур, до которых среднему программисту дела нет. Поэтому первая часть людей продолжает говорить, что в практическом поле nullptr - это ноль.

Но есть красивый пример, иллюстрирующий что это не так.


Природа заблуждения растет, как мне кажется, из проверки подстановкой указателя в if.

struct S {
char a;
char b;
int c;
int d;
};

int main()
{
auto s = S{'1', '2', 3, 4};

S* pS = nullptr;

if (!pS) {
std::cout << "pS" << std::endl;
std::cout << std::hex << "ptr: "<< *(int*)(&pS) << std::endl;
}

pS = &s;

if (pS) {
std::cout << "pS" << std::endl;
std::cout << std::hex << "ptr: "<< *(int*)(&pS) << std::endl;
}
}


Ну тут все очевидно. Выведет вот это:

pS
ptr: 0
pS
ptr: 7ede1034


Указатель нулевой, и логично, что проверка if (var) - это проверка на ноль, как мы и привыкли.
Но помимо указателя на объект в С++ есть еще указатель на члены класса.

    char S::* pSm = nullptr;

pSm = &S::a;

if (pSm) {
std::cout << "pS.a" << std::endl;
std::cout << std::dec << "value: " << s.*pSm << std::endl;
std::cout << std::hex << "ptr: "<< *(int*)(&pSm) << std::endl;
}

pSm = &S::b;


if (pSm) {
std::cout << "pS.b" << std::endl;
std::cout << std::dec << "value: " << s.*pSm << std::endl;
std::cout << std::hex << "ptr: "<< *(int*)(&pSm) << std::endl;
}


Что здесь важно. Указатель на член класса - это не адрес в памяти. Это смещение относительно адреса объекта к адресу члена. Таким образом, указатель на первый член класса всегда будет 0.

pS.a
value: 1
ptr: 0
pS.b
value: 2
ptr: 1


Еще более занятно, что прошла проверка if (pSm) для нуля. Потому что это валидное и даже ожидаемое значение, а в бинарном коде эта проверка выглядит так:

cmp     rax, -1


Ну и тут можно догадаться, но мы выведем кодом ниже и чему равен nullptr для членов класса:

    pSm = nullptr;

if (!pSm) {
std::cout << "pS.nullptr" << std::endl;
std::cout << std::dec << "value: " << s.*pSm << std::endl;
std::cout << std::hex << "ptr: "<< *(int*)(&pSm) << std::endl;
}

if (pSm) {
std::cout << "Unreacheable" << std::endl;
}



pS.nullptr
value:
ptr: ffffffff


значение nullptr - это минус один. И это без всяких эзотерических архитектур, в рамках одной и той же программы у нас есть два разных значения для nullptr.

Весело в С++ однако.....
godbolt.org Compiler Explorer - C++ struct S { char a; char b; int c; int d; }; int main() { auto s = S{'1', '2', 3, 4}; S* pS = nullptr; if (!pS) { std::cout << "pS" << std::endl; std::cout << std::hex << "ptr: "<< *(int*)(&pS) << std::endl; …
  • 🔥 20
  • 👍 1
  • 🤔 1
  • 😢 1
More from @cpp_durka
  1. Sep 8, 2026Мошенники заставили пенсионерку из Москвы переписать квартиру на Rust
  2. Aug 31, 2026Всяко разное болезненное есть в С++, из всего болезненного одно из самых болезненных - это…
  3. Aug 24, 2026Если кто не знаком с библиотекой nlohmann/json - она прекрасна. Мои мысли о том, как должн…
  4. Aug 21, 2026#толькосвоимемы Код взят тут. if (dim == 0) idx_dim = i0; else if (dim == 1) idx_dim = i1;…
  5. Aug 17, 2026Ладно, искать баги в компиляторах весело, но недостаточно. Давайте поиграемся в чуть более…
  6. Aug 10, 2026Ладно, разумеется прошлый пост был набросом. Никогда не обновляйте компиляторы без очень с…
Threads Profile ViewerView any public Threads profile without an account.Open ThreadLook →Writing with AI? Make it sound human.Metric37 rewrites AI drafts so they read naturally. Free AI detector, 1,500 words free.Try Metric37 →