5

Что такое `unsigned char`?

13

Проблема: Использование unsigned char в C/C++

В C/C++ существует тип данных unsigned char, который часто вызывает вопросы у разработчиков. В частности, возникает необходимость понять, для чего он используется и чем он отличается от обычного char.

С одной стороны, char может быть знаковым (signed) или беззнаковым (unsigned), в зависимости от реализации компилятора, и, как правило, используется для хранения символов. С другой стороны, unsigned char является беззнаковым типом, который может хранить только неотрицательные значения в диапазоне от 0 до 255.

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

Пожалуйста, дайте разъяснения по следующими вопросам:

  1. Когда следует использовать unsigned char вместо обычного char?
  2. Какие примеры использования unsigned char вы можете привести в контексте работы с данными?
  3. Как различия между signed char, unsigned char и обычным char могут повлиять на производительность или поведение программы?

5 ответ(ов)

6

В C++ есть три разных типа символов:

  1. char
  2. signed char
  3. unsigned char

1. char

Если вы используете символьные типы для текста, применяйте неквалифицированный char:

  • это тип символьных литералов, таких как 'a' или '0' (в C++ это именно так, в C их тип - int)
  • это тип, из которого состоят C-строки, например, "abcde"

Хотя char также работает как числовое значение, его знак (подписанность или беззнаковость) не определен. Будьте осторожны при сравнении символов через неравенства - хотя если вы ограничите себя символами ASCII (0-127), то вы вряд ли столкнетесь с проблемами.

2. signed char / 3. unsigned char

Если вы используете символьные типы как числа, используйте:

  • signed char, который дает вам по крайней мере диапазон от -127 до 127. (обычно от -128 до 127)
  • unsigned char, который дает вам по крайней мере диапазон от 0 до 255. Это может быть полезно для отображения октета, например, в виде шестнадцатеричного значения.

"По крайней мере", потому что стандарт C++ только указывает минимальный диапазон значений, который каждый числовой тип должен покрывать. sizeof(char) должен равняться 1 (т.е. один байт), но в теории байт может составлять, например, 32 бита. sizeof все равно будет указывать его размер как 1 - это означает, что у вас может быть sizeof(char) == sizeof(long) == 1.

0

Поскольку считаю, что это действительно необходимо, хочу изложить некоторые правила C и C++ (в этой части они одинаковы). Первое: все биты переменной типа unsigned char участвуют в определении значения любого объекта типа unsigned char. Второе: unsigned char явно обозначен как беззнаковый.

Недавно у меня произошла дискуссия с одним человеком о том, что происходит при преобразовании значения -1 типа int в unsigned char. Он был против того, чтобы считать, что результирующий unsigned char имеет все свои биты, установленные в 1, поскольку его беспокоила проблема представления знака. Но ему не о чем беспокоиться. Исходя из данного правила, преобразование выполняется должным образом:

Если новый тип беззнаковый, значение преобразуется путем многократного сложения или вычитания большего на единицу, чем максимальное значение, которое может быть представлено в новом типе, пока значение не окажется в пределах нового типа. (параграф 6.3.1.3p2 в черновике C99)

Это математическое описание. В C++ это описывается в терминах модульной арифметики, что приводит к тому же правилу. В любом случае, что не гарантируется, так это то, что все биты целого числа -1 равны 1 до преобразования. Так на чем основано наше утверждение, что результирующий unsigned char имеет все свои CHAR_BIT битов, установленные в 1?

  1. Все биты участвуют в определении его значения — то есть, в объекте нет битов заполнения.
  2. Если сложить один раз UCHAR_MAX + 1 к -1, мы получим значение в пределах диапазона, а именно UCHAR_MAX.

Этого вполне достаточно! Так что, когда вам нужно создать unsigned char, у которого все биты равны 1, вы можете сделать следующее:

unsigned char c = (unsigned char)-1;

Также следует отметить, что преобразование — это не просто усечение старших битов. Удачное обстоятельство для дополнительного представления заключается в том, что в этом случае действительно происходит только усечение, но это не обязательно верно для других представлений знака.

0

unsigned char часто используется в компьютерной графике, где обычно (хотя не всегда) каждому компоненту цвета соответствует один байт. Обычно RGB (или RGBA) цвет представляется как 24 (или 32) бита, где каждый бит — это unsigned char. Поскольку значения unsigned char находятся в диапазоне [0, 255], их интерпретация выглядит следующим образом:

  • 0 означает полное отсутствие данного компонента цвета.
  • 255 означает 100% насыщенности данного цветового пигмента.

Таким образом, цвет RGB для красного будет представлен как (255, 0, 0) — это значит (100% красного, 0% зеленого, 0% синего).

Почему бы не использовать signed char? Аритметика и побитовые операции становятся проблематичными. Как уже было объяснено, диапазон signed char сдвинут на -128. Простой и наивный (в основном неиспользуемый) способ конвертации RGB в оттенки серого — усреднение всех трех цветовых компонентов, однако это приводит к проблемам, когда значения цветовых компонентов отрицательные. Красный цвет (255, 0, 0) усредняется до (85, 85, 85) при использовании арифметики unsigned char. Однако, если бы значения были signed char (127, -128, -128), мы бы получили (-99, -99, -99), что в пространстве unsigned char эквивалентно (29, 29, 29), что является некорректным результатом.

0

signed char имеет диапазон от -128 до 127, а unsigned char — от 0 до 255.

Тип char будет эквивалентен либо signed char, либо unsigned char, в зависимости от компилятора, но это отдельный тип.

Если вы работаете со строками в C-стиле, просто используйте char. Если вам нужно использовать символы для арифметических операций (что довольно редко), указывайте явно signed или unsigned для обеспечения переносимости.

0

unsigned char в языке C занимает только неотрицательные значения, то есть диапазон от 0 до 255.

С другой стороны, signed char может принимать как положительные, так и отрицательные значения, его диапазон составляет от -128 до +127.

Чтобы ответить на вопрос, пожалуйста, войдите или зарегистрируйтесь