Если я выполнил следующий код в C:
#include uint16_t a = 4000; uint16_t b = 8000; int32_t c = a - b; printf("%d", c);
В результате он правильно выводит «-4000». Тем не менее, я немного смущен: не должно быть арифметического переполнения при вычитании большего числа без знака из другого? Какие правила кастинга здесь играют? Этот вопрос кажется немного noobish, поэтому любые ссылки были бы весьма признательны.
Проблема на самом деле несколько сложная. Операнды арифметических выражений преобразуются с использованием определенных правил, которые вы можете видеть в разделе 3.2.1.5 Стандарта (C89) . В вашем случае ответ зависит от типа uint16_t
. Если он меньше, чем int
, скажем, short int
, то операнды преобразуются в int
и вы получаете -4000, но в 16-битной системе uint16_t
может быть unsigned int
и преобразование в подписанный тип не произойдет автоматически.
Короткий ответ заключается в том, что все они продвигаются до int
во время вычитания. Для долгого ответа см. Раздел 6.3.1.1 стандарта C , в котором говорится о целых акциях в арифметических выражениях. Соответствующий язык из стандарта:
Если
int
может представлять все значения исходного типа, значение преобразуется вint
; в противном случае он преобразуется вunsigned int
. Они называются целыми акциями . Все остальные типы не изменяются целыми акциями.
Детали там тоже, но они становятся довольно неприятными.
Оба операнда продвигаются до int32_t
во время вычитания. Если результат был больше максимального значения для int32_t
вы бы увидели переполнение.
На самом деле существует переполнение, но C не говорит вам.
Переполнение оставляет значение, которое составляет -4000, когда интерпретируется как целое число со знаком. Это работает в соответствии со стандартными машинами.
Попробуйте интерпретировать результат как unsigned, и вы заметите, что (u1-u2) оценивает какое-то, казалось бы, несвязанное число, когда u1