Расширение целочисленных типов

Если новый тип шире, чем старый (sizeof), то надо каким-то образом расширить значение

Смотрим на то, был ли тип знаковым

Расширение будет арифметическое: Signed ⇒ если в старшем бите была единичка, то значение будет расширено единичками, чтобы у нас число осталось отрицательным Unsigned ⇒ значение будет расширяться нулями

Screenshot 2022-01-12 at 14.12.35.png

Засады бывают в том, что тип char по стандарту бывает знаковым и беззнаковым

При расширении char, мы не знаем, как именно он расширится

⇒ надо в явном виде написать, знаковый он или беззнаковый

Screenshot 2022-01-12 at 14.13.39.png

Если мы складываем два выражения разных размеров и разной знаковости, то они все приводятся к максимальному размеру аргумента; если есть и знаковые и беззнаковые операнды, то все выражение становится беззнаковым

Q: Если значение не помещается в long long, но помещается в unsigned long long, то это UB?

A: Signed long long и unsigned long long имеют одинаковый sizeof (=64 бита) ⇒ любое значение unsigned ll помещается в signed ll

Проблема начинается в обратную сторону: мы взяли большое число и попытались положить его в маленький тип. Если результирующий тип unsigned, то все прекрасно (старшие биты обрезаются, а младшие, сколько поместятся, помещаются в новое значение), иначе (signed) значащие биты обрезались, и получается UB

Screenshot 2022-01-12 at 14.20.15.png

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

Возникло знаковое переполнение

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

    Взяли максимальный int, прибавили единичку, возникло знаковое переполнение

Screenshot 2022-01-12 at 14.25.57.png