Теоретически, ваш код может работать на машине, которая запрещает один битовый шаблон в char
со знаком.Он может использовать свои представления дополнения или величины знака отрицательных целых чисел, в которых один битовый шаблон будет интерпретироваться как 0 с отрицательным знаком.Даже на архитектурах с двумя дополнениями стандарт позволяет реализации ограничивать диапазон отрицательных целых чисел так, чтобы INT_MIN == -INT_MAX
, хотя я не знаю ни одной реальной машины, которая делает это.
Итак, согласно §6.2.6.2p2, может быть одно значение со знаком, которое реализация может рассматривать как представление прерывания:
Какое из этих [представлений отрицательных целых чисел] применяется, определяется реализацией, как и является лизначение со знаковым битом 1 и всеми битами значения ноль (для первых двух [знаковая величина и дополнение к двум]) или со знаковым битом и всеми битами значения 1 (для дополнения единиц) является представлением прерывания или нормальным значением.В случае знака, величины и их дополнения, если это представление является нормальным значением, оно называется отрицательный ноль .
(не может быть никаких других значений ловушек длятипы символов, потому что §6.2.6.2 требует, чтобы signed char
не имел никаких битов заполнения, что является единственным другим способом, которым может быть сформировано представление прерывания. По той же причине ни один битовый шаблон не является представлением прерывания для unsigned char
.)
Итак, если эта гипотетическая машина имеет реализацию C, в которой подписано char
, то возможно, что копирование произвольного байта через char
потребует копирования представления прерывания.
Для целочисленных типов со знаком, кроме char
(если оно подписано) и signed char
, чтение значения, представляющего собой ловушку, является неопределенным поведением.Но §6.2.6.1 / 5 позволяет читать и записывать эти значения только для символьных типов :
Некоторые представления объекта не должны представлять значение типа объекта.Если сохраненное значение объекта имеет такое представление и читается выражением lvalue , которое не имеет символьного типа , поведение не определено.Если такое представление создается побочным эффектом, который изменяет весь или любую часть объекта выражением lvalue, которое не имеет символьного типа, поведение не определено.Такое представление называется представлением ловушек. (выделение добавлено)
(Третье предложение немного неуклюже, но для упрощения: сохранение значения в памяти - это «побочный эффект, который изменяет весь объект»,так что это разрешено.)
Короче говоря, благодаря этому исключению, вы можете использовать char
в реализации memcpy
, не беспокоясь о неопределенном поведении.
Однако то же самоене верно для strcpy
.strcpy
должен проверить завершающий байт NUL, который завершает строку, что означает, что ему нужно сравнить значение, которое он читает из памяти, с 0. И операторы сравнения (в действительности, все арифметические операторы) сначала выполняют целочисленное продвижение своих операндов,преобразует char
в int
.Целочисленное продвижение представления ловушек - это неопределенное поведение, насколько я знаю, поэтому в гипотетической реализации C, работающей на гипотетической машине, вам потребуется использовать unsigned char
, чтобы реализовать strcpy
.