signed char
, char
и unsigned char
- все целочисленные типы.Для простоты я предполагаю, что CHAR_BIT равен 8, а подписанные типы являются дополнением 2.Итак:
signed char
это число от -128 до + 127 unsigned char
это число от 0 до 255 char
либотот же диапазон, что и signed char
, или тот же диапазон, что и unsigned char
, в зависимости от вашей реализации на языке C.
Что касается C, то символ - это просто число в пределах диапазонаchar
тип (хотя различные символьные функции, такие как tolower
, требуют приведения значения к типу без знака при входе, даже если char
подписано).
Итак, signed char
и unsigned char
являются оба представление символа в битовой форме.Для чисел в диапазоне от 0 до +127 они оба используют одно и то же представление (есть только один способ представить положительные числа в двоичном виде).Для чисел вне этого диапазона подписанное представление отрицательного числа n
- это те же биты, что и беззнаковое представление n + 256
(определение дополнения к 2).
Причина, по которой этот код использует unsigned char
, заключается в том, чтоэтот сдвиг вправо с отрицательным знаком имеет результат, определенный реализацией.Сдвиг влево с отрицательным знаком имеет неопределенное поведение .Обычно сдвиг влево ведет себя так же, как и для значений без знака, что нормально, но сдвиг вправо вставляет биты слева со значением 1, так называемый «арифметический сдвиг», что здесь не так.Беззнаковые значения всегда смещаются в нули, и именно смещение нуля позволяет этому коду построить две части повернутого результата и / или их вместе.
Итак, предполагая, что входное значение x = 254 (11111110
) и n = 1, мы получим:
x << 7 is 0111111100000000
x >> 1 is 01111111
| is 0111111101111111
convert to unsigned char to return is 01111111
Если бы мы использовали тип со знаком вместо unsigned char
, мы вполне могли бы получить:
x is -2 11111110
x << 7 is 11111111111111111111111100000000 (assuming 32-bit int, since
smaller types are always promoted to int for arithmetic ops)
x >> 1 is implementation-defined, possibly
11111111111111111111111111111111
| is 11111111111111111111111111111111
convert to signed char to return is -1
Так чтобитовая манипуляция с беззнаковым символом приводит к правильному ответу, повернутому на 1 бит, чтобы переместить 0 от конца к началу.Битовая манипуляция со знаком со знаком, возможно, дает неправильный результат, может дать правильный результат, если отрицательные знаковые значения делают логический сдвиг вправо, но в действительно необычных реализациях может делать что угодно.
В значительной степени всегда для битовыхЗадачи манипуляции, такие как поворот, вы хотите использовать неподписанные типы.Он удаляет зависимость от реализации (отличную от ширины типа) и избавляет от необходимости отдельно рассуждать о отрицательных и неотрицательных значениях.