Intereting Posts
Используйте printf для форматирования поплавков без десятичных знаков, если только завершение 0s Что происходит с указателем FILE после закрытия файла? Я хочу, чтобы иметь возможность печатать трассировки стека java style в c Документация macOS для структур в Security.h Что касается проверки файла или каталога Ошибка с RegOpenKeyEx Как бесконечность представлена ​​в C двойной? Сбой жесткого отслеживания памяти – при работе с Valgrind выполняется правильно, без ошибок Смешивание объявлений с внешним, статическим и отсутствующим спецификатором хранилища в глобальной области видимости Динамический массив в C – Является ли мое понимание malloc и realloc правильным? С чего начать читать исходный код SQLite? Объявление двумерного массива неизвестного размера, C Как рассчитать смещение UTC от имени часового пояса IANA в C mmap () vs read () Поменяйте два указателя с помощью XOR

C целочисленное поведение при переполнении при назначении целых чисел большей ширины

Если я выполнил следующий код в 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