Как было отмечено в комментариях, это связано с неопределенным поведением.
Современные компиляторы могут (ab) использовать неопределенное поведение для упрощения, сокращения и ускорения скомпилированного кода без нарушения каких-либо правил. Я предлагаю вам прочитать эту прекрасную статью об опасностях UB.
Трудно понять, что именно происходит, потому что оптимизатор становится чрезвычайно сложным, но вот пример того, что компилятор может делать с вашей функцией.
(1) int isTmax(int x)
(2) {
(3) int temp = x + x + 2;
(4) int result = !temp & (!!(~x));
(5) return result;
(6) }
В строке 3 вы складываете два целых числа со знаком. Если ваша программа вызывает эту функцию только один раз с 0x7fffffff
, компилятор уже знает, что код производит только целочисленное переполнение. Там есть поворот с этим кодом; так как вы добавляете 2 к операции переполнения, компилятор может предположить, что значение будет положительным и больше двух, ради того, что будет дальше.
В строке 4 !temp
переводится в логическую константу false
, поскольку предполагается, что temp является положительным значением. Далее and
; поскольку левое значение равно false (или 0), result
всегда заканчивается 0. Если результат всегда равен нулю, оптимизатор также может удалить все переменные и операции.
По сути, после оптимизации ваша функция выглядит следующим образом:
int isTmax(int x)
{
return 0;
}
Добавляя printf
внутри функции, вы заставляете оптимизатор де-оптимизации, и в итоге вы получаете тот же код, который вы получаете, когда не оптимизируете свою программу.