TGViewer
Грокаем C++ Грокаем C++ @grokaemcpp · 9.36K subscribers
Post #1074 4K
​​WAT
#опытным

Сколько будет х/х?

Как ни странно, на этот вопрос есть множество ответов.

Математический ответ: при x != 0 выражение вырождается в единицу. Если же x = 0, то значение выражения неопределено. x=0 приводит к неопределенности вида 0/0, у которого нет корректного значения.

Какой же ответ у С++?

#include <iostream>

int main() {
int x = 0;
std::cout << x/x << std::endl;
}


Ответ будет 1!

На те вот ссылочку на годболт, если не верите.

#ЧЗХ? Компьютер считать чтоли не умеет?

По ссылочке на самом деле только вывод gcc показан. И он действительно выдает 1.

Но на кланге при запуске программа получает сигнал SIGFPE, а на msvc выдается вот такая цифирь 3221225620.

Понятное дело, что деление на 0 - это UB, и это явно видно по результатам запуска на разных компиляторах.

Если вы думали, что проблема проявляется только оптимизациях - нет. Даже на -O0 все равно gcc единичку выдает.

Тогда как могла появиться единичка?

С какой-то стороны этот вопрос не имеет смысла, потому что при UB компилятор волен поступать, как ему вздумается. Но этот конкретный пример показывает одну из популярных моделей поведения компилятора при UB.

С точки зрения разработчика С++ UB - это скорее плохо. Некоторые из нас идут на риск, когда понимают реальный эффект на конкретном компиляторе и железе, но в большинстве кейсов мы стараемся избегать UB.

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

UB в данном случае произойдет только при x=0. Тогда компилятор просто выкидывает этот вариант из анализа, притворяется, что такого не может быть. Тогда выражение x/x действительно становится равным единице.

Компилятор применил константную свёртку (constant folding) — одно из базовых преобразований, которое работает даже на нулевом уровне оптимизации. Он увидел выражение x / x, где x — целочисленная переменная, и, как мы все делали в школе, сократил числитель и знаменатель. В итоге на консоль вывелась единичка.

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

volatile int x = 0;
std::cout << x/x << std::endl;


Это ключевое слово запрещает компилятору делать предположения о значении переменной и заставляет чего честно читать переменную из памяти.

Do not trust programmers. Stay cool.

#compiler
  • 🔥 25
  • ❤ 14
  • 👍 9
More from @grokaemcpp
  1. Oct 8, 2026​​Strict weak ordering #опытным На первый взгляд, всё выглядит рабочим: мы создаём 40 зака…
  2. Oct 7, 2026​​Где-то баг... #опытным Вот вам код: struct Order { int price; int id; }; int main() { st…
  3. Oct 5, 2026Откуда spurious wakeup на кондваре? #опытным У кондваров есть метод std::condition_variabl…
  4. Oct 1, 2026​​Stacktrace. Tips #опытным Чтобы полноценно работать со стандартными трейсами, нужно знат…
  5. Sep 28, 2026​​Stacktrace #опытным Одна из проблема исключений - непонятно, откуда оно прилетело. Ну да…
  6. Sep 25, 2026​​std::spanstream #опытным Радостная весть для всех, кто пользуется iostreams! В C++23 доб…
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 →