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

В C/С++ для чего используется `unsigned char`? Как он отличается от обычного `char`?

 

В С++ существуют три различных типа символов:

* `char`
* `signed char`
* `unsigned char`

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

* это тип символов, таких как `'a'` или `'0'`.
* это тип, который составляет строки C, такие как `"abcde"`

Он также работает как числовое значение, но не указано, обрабатывается ли это значение как подписанное или unsigned. Остерегайтесь сопоставления персонажей с помощью неравенств - хотя, если вы ограничиваете себя ASCII (0-127), вы почти безопасны.

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

* `signed char`, который дает вам, по крайней мере, диапазон от -127 до 127. (От -128 до 127).
* `unsigned char`, который дает вам как минимум диапазон от 0 до 255.

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

 

Это зависит от реализации, так как стандарт C НЕ определяет подписанность `char`. В зависимости от платформы char может быть `signed` или `unsigned`, поэтому вам нужно явно запросить `signed char` или `unsigned char`, если от этого зависит ваша реализация. Просто используйте `char`, если вы намерены представлять символы из строк, поскольку это будет соответствовать тому, что ваша платформа помещает в строку.

Разница между `signed char` и `unsigned char` такова, как вы ожидали. На большинстве платформ `signed char` будет иметь 8-битовое число с двумя дополнениями от `-128` до `127`, а `unsigned char` будет 8-разрядным целым без знака (`0` до `255`). Обратите внимание, что стандарт НЕ требует, чтобы типы `char` имели 8 бит, только `sizeof(char)` return `1`. Вы можете получить число бит в char с помощью `CHAR_BIT` в `limits.h`. Хотя сегодня есть несколько платформ, где это будет нечто большее, чем `8`.

В этом выпуске есть хорошее резюме этой проблемы .

Как уже упоминалось, поскольку я опубликовал это, вам лучше использовать `int8_t` и `uint8_t`, если вы действительно хотите представлять маленькие целые числа.

 

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

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

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

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

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

Это достаточно, на самом деле! Поэтому, когда вы хотите, чтобы `unsigned char` имел все свои биты один, вы делаете

```
unsigned char c = (unsigned char)-1;

```

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

 

Как, например, использование unsigned char:

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

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

Таким образом, вы получите RGB красный как (255,0,0) → (100% красный, 0% зеленый, 0% синий).

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

 

Если вы хотите использовать символ как маленькое целое число, самый безопасный способ сделать это - это типы `int8_t` и `uint8_t`.

 

 `char` и `unsigned char` не гарантируются как 8-разрядные типы на всех платформах, они гарантированно будут 8 бит или больше. На некоторых платформах [9-битный, 32-разрядный или 64-разрядный байты](http://www.parashift.com/c++-faq-lite/intrinsic-types.html#faq-26.4). Однако наиболее распространенные платформы сегодня (Windows, Mac, Linux x86 и т.д.) Имеют 8-разрядные байты.

 

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

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

Если вы используете строки стиля C, просто используйте `char`. Если вам нужно использовать символы для арифметики (довольно редко), укажите явно подписанный или неподписанный для переносимости.

 

Беззнаковое char представляет собой (без знака) байтовое значение (от 0 до 255). Возможно, вы думаете о "char" в терминах "персонажа", но это действительно числовое значение. Обычный "char" подписан, поэтому у вас есть 128 значений, и эти значения сопоставляются символам с использованием кодировки ASCII. Но в любом случае то, что вы храните в памяти, является байтовым значением.

 

В терминах прямых значений используется обычный char, когда известно, что значения находятся между `CHAR_MIN` и `CHAR_MAX`, а unsigned char обеспечивает двойной диапазон на положительном конце. Например, если `CHAR_BIT` равно 8, диапазон регулярных `char` гарантируется только [0, 127] (поскольку он может быть подписан или без знака), а `unsigned char` будет [0, 255] и `signed char` будет [-127, 127].

В терминах того, для чего он использовался, стандарты позволяют напрямую преобразовывать объекты POD (простые старые данные) в массив без знака char. Это позволяет вам просматривать представление и битовые шаблоны объекта. Для char или подписанного char та же гарантия безопасного кастомизации типа не существует.

 

 `unsigned char` принимает только положительные значения.... например  **0** до  **255**

 где as

 `signed char` принимает как положительные, так и отрицательные значения.... например  **-128** до  **+127**

 

Если вам нравится использовать различные типы определенной длины и подписи, вам, вероятно, лучше работать с uint8\_t, int8\_t, uint16\_t и т.д. просто потому, что они делают именно то, что они говорят.

 

unsigned char - это основа всей хитрости. Почти во всех компиляторах для всей платформы unsigned char является просто BYTE. Целое число без знака (обычно) 8 бит. который можно рассматривать как небольшое целое или пакет бит.

В зависимости от того, как сказал кто-то другой, стандарт не определяет знак char. поэтому у вас есть 3 разных типа "char": char, подписан char, unsigned char.

 

Некоторые поисковики обнаружили [это](https://bytes.com/forum/thread61480.html), где люди обсуждали это.

Беззнаковый char является в основном одиночным байтом. Таким образом, вы использовали бы это, если вам нужен один байт данных (например, возможно, вы хотите использовать его для установки и включения флажков для функции, как это часто делается в Windows API).

 

  **беззнаковые числа** `always positive or zero` и подчиняются `laws of arithmetic modulo 2^n`, где `n` - количество бит в типе.

  **пример**: если символы имеют 8 бит, переменные `unsigned char` имеют значения между `0 and 255`, а `signed chars` имеют значения между `-128 and 127.`

 

unsigned char принимает только положительные значения: от 0 до 255
подписанный char принимает положительные и отрицательные значения: от -128 до +127

 

Беззнаковый char использует бит, который зарезервирован для знака обычного char как еще один номер. Это изменяет диапазон на [0 - 255] в отличие от [-128 - 127].

Обычно символы без знака используются, когда вам не нужен знак. Это будет иметь значение при выполнении таких вещей, как смещение битов (сдвиг расширяет знак) и другие вещи при работе с char как байт, а не использование его как числа.

 

цитируется из книги "c программирования laugage":

К char или любому целому числу может применяться квалификатор `signed` или `unsigned`. беззнаковые числа
всегда положительны или равны нулю и подчиняются законам арифметики по модулю 2 ^ n, где n - число
бит в типе. Так, например, если символы имеют 8 бит, переменные без знака char имеют значения
между 0 и 255, в то время как подписанные символы имеют значения от -128 до 127 (в два раза
добавьте машину.) Являются ли простые символы подписанными или неподписанными являются зависящими от машины,
но печатные символы всегда положительны.