Ответ 1
Сводка: результат определяется реализацией и, скорее всего, будет -1
, но он усложняется, по крайней мере, в принципе.
Правила переполнения различаются для операторов по сравнению с конверсиями, а для подписанных типов - неподписанных типов - и правила преобразования изменены между C90 и C99.
С C90 переполнение оператора со знаками целочисленных операндов ( "переполнение" означает, что математический результат не может быть представлен в типе выражения) имеет поведение undefined. Для целых операндов без знака поведение корректно определяется как обычное обертывание (строго говоря, стандарт не называет это "переполнением" ). Но ваше выражение:
char foo = 255;
не использует каких-либо операторов (=
является инициализатором, а не назначением), поэтому в этом случае ничего не применяется.
Если тип char
может представлять значение 255
(которое истинно либо из простого char
, либо без знака, либо если CHAR_BIT >= 9
), то, конечно, поведение корректно определено. Выражение int
255
неявно преобразуется в char
. (Так как CHAR_BIT >= 8
, этот случай невозможен для вызова беззнакового обхода.)
В противном случае преобразование дает результат, который не может быть сохранен в char
.
Начиная с C90, результат преобразования определяется реализацией - это означает, что он гарантировал установить foo
на некоторое значение в диапазоне типа char
, и вы можете определить, что это значение, путем чтения документацию по внедрению, которая должна рассказать вам, как работает преобразование. (Я никогда не видел реализации, где хранимое значение - это что-то иное, чем -1
, но любой результат возможен в принципе.)
C99 изменило определение, так что переполняющее преобразование в подписанный тип либо дает результат, определенный реализацией, либо повышает сигнал, определяемый реализацией.
Если компилятор решает сделать последнее, он должен документировать, какой сигнал поднят.
Итак, что происходит, если сигнал, определяемый реализацией? В разделе 7.14 стандарта говорится:
Полный набор сигналов, их семантика и их значение по умолчанию обработка определяется реализацией
Не совсем понятно (мне), какой диапазон возможных поведений для "обработки по умолчанию" сигналов. В худшем случае, я полагаю, такой сигнал может прекратить программу. Вы можете или не сможете определить обработчик сигнала, который поймает сигнал.
7.14 также говорится:
Если и когда функция вернется, если значение sig SIGFPE, SIGILL, SIGSEGV или любое другое значение, определяемое реализацией что соответствует расчетному исключению, поведение undefined; в противном случае программа возобновит выполнение в тот момент, когда она была прерываться.
но я не думаю, что это применимо, поскольку переполняющее преобразование не является "вычислительным исключением", поскольку этот термин используется здесь. (Если сигнал, определяемый реализацией, не будет SIGFPE
, SIGILL
или SIGSEGV
- но это будет глупо).
Таким образом, в конечном счете, если реализация решает повысить сигнал в ответ на переполняющее преобразование, поведение (а не только результат) определяется, по крайней мере, как реализация, и могут быть обстоятельства, в которых это может быть undefined. В любом случае, похоже, нет никакого переносного способа борьбы с таким сигналом.
На практике я никогда не слышал о реализации, которая использует новую формулировку на C99. Для всех компиляторов, о которых я слышал, результат преобразования определяется реализацией - и, вероятно, дает то, что вы ожидаете от усечения 2-го уровня. (И я совсем не убежден, что это изменение на C99 было хорошей идеей. Если ничего не было, он сделал этот ответ примерно в 3 раза до тех пор, пока это было бы иначе.)