Что такое `unsigned char`?
Проблема: Использование unsigned char в C/C++
В C/C++ существует тип данных unsigned char, который часто вызывает вопросы у разработчиков. В частности, возникает необходимость понять, для чего он используется и чем он отличается от обычного char.
С одной стороны, char может быть знаковым (signed) или беззнаковым (unsigned), в зависимости от реализации компилятора, и, как правило, используется для хранения символов. С другой стороны, unsigned char является беззнаковым типом, который может хранить только неотрицательные значения в диапазоне от 0 до 255.
Следует рассмотреть конкретные случаи, когда использование unsigned char оправдано, например, при работе с двоичными данными, изображениями или сетевыми протоколами, где важно избежать знаковых значений и работать только с положительными целыми числами.
Пожалуйста, дайте разъяснения по следующими вопросам:
- Когда следует использовать
unsigned charвместо обычногоchar? - Какие примеры использования
unsigned charвы можете привести в контексте работы с данными? - Как различия между
signed char,unsigned charи обычнымcharмогут повлиять на производительность или поведение программы?
5 ответ(ов)
В C++ есть три разных типа символов:
charsigned charunsigned 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.
Поскольку считаю, что это действительно необходимо, хочу изложить некоторые правила 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?
- Все биты участвуют в определении его значения — то есть, в объекте нет битов заполнения.
- Если сложить один раз
UCHAR_MAX + 1к-1, мы получим значение в пределах диапазона, а именноUCHAR_MAX.
Этого вполне достаточно! Так что, когда вам нужно создать unsigned char, у которого все биты равны 1, вы можете сделать следующее:
unsigned char c = (unsigned char)-1;
Также следует отметить, что преобразование — это не просто усечение старших битов. Удачное обстоятельство для дополнительного представления заключается в том, что в этом случае действительно происходит только усечение, но это не обязательно верно для других представлений знака.
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), что является некорректным результатом.
signed char имеет диапазон от -128 до 127, а unsigned char — от 0 до 255.
Тип char будет эквивалентен либо signed char, либо unsigned char, в зависимости от компилятора, но это отдельный тип.
Если вы работаете со строками в C-стиле, просто используйте char. Если вам нужно использовать символы для арифметических операций (что довольно редко), указывайте явно signed или unsigned для обеспечения переносимости.
unsigned char в языке C занимает только неотрицательные значения, то есть диапазон от 0 до 255.
С другой стороны, signed char может принимать как положительные, так и отрицательные значения, его диапазон составляет от -128 до +127.
Как изменить цвет вывода echo в Linux
Разница между const int*, const int * const и int * const?
Почему переменные нельзя объявлять в операторе switch?
Как вывести список символов из .so файла?
`unsigned int` против `size_t`: когда и что использовать?