2016-07-10 2 views
1

Во время чтения книги о programmign трюков я увидел, что -0x80000000 + -0x80000000 = 0. Это не имеет смысла для меня, так что я написал быстро программу C ниже, чтобы проверить и действительно ответ 0:Почему -0x80000000 + -0x80000000 == 0?

#include <stdio.h> 

int main() 
{ 
    int x = -0x80000000; 
    int y = -0x80000000; 

    int z = x + y; 

    printf("Z is: %d", z); 
    return 0; 
} 

Может ли кто-нибудь пролить свет на то, почему? Я видел что-то о переполнении, но я не вижу, как переполнение вызывает 0, а не исключение или другую ошибку. Я ничего не предупреждаю.

+1

Да, это переполнение. Нет, C обычно не предупреждает или не исключает исключения при переполнении целых чисел. Вы видите 0, потому что нижние 32 бита фактического ответа равны 0, и когда происходит переполнение целого числа, вы, как правило, получаете ответ по модулю 4294967296, то есть по модулю 2^32. –

ответ

2

Что происходит здесь, это целочисленное переполнение, которое равно undefined behavior, потому что точное представление целых чисел со знаком не определено.

На практике, однако, большинство машин используют представление дополнения 2 для целых чисел со знаком, и эта конкретная программа использует это.

0x80000000 - целочисленная константа без знака. - отрицает это, меняя выражение на подписанное. Предполагая, что int 32-бит в вашей системе, это значение все еще подходит. Фактически, это наименьшее значение, которое может содержать подписанный 32-разрядный int, а шестнадцатеричное представление этого числа - 0x80000000.

При добавлении номеров в представлении дополнений 2, у него есть функция, которая вам не нужно беспокоиться о знаке. Они добавляются точно так же, как и беззнаковые числа.

Так что, когда мы добавляем x и y, мы получаем следующее:

0x80000000 
+ 0x80000000 
------------- 
    0x100000000 

Поскольку int в системе является 32-разрядным, лишь нижним 32 бит сохраняется. И значение этих бит равно 0.

Снова обратите внимание, что это фактически неопределенное поведение. Он работает, потому что ваша машина использует представление дополнения 2 для целых чисел со знаком, а int - 32-разрядная. Это характерно для большинства машин/компиляторов, но не для всех.

+1

Тип '0x80000000' - это реализация. Он может быть подписан. – 2501

+2

Простое отрицание неподписанного типа не даст подписанного типа. При некоторых предположениях, в случае OP, значение без знака обертывается обратно к (положительному) значению 0x80000000. – 2501

+0

спасибо, помог мне понять, что происходит. – MHartley

1

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

Результат не имеет смысла без дополнительной информации. Если вы хотите получить определенный ответ, обратитесь к диапазонам типов для вашей архитектуры и убедитесь, что результаты присвоений и арифметики соответствуют их соответствующим типам.

Смежные вопросы