В C / C ++, для чего unsigned char
используется? Чем он отличается от обычного char
?
В C / C ++, для чего unsigned char
используется? Чем он отличается от обычного char
?
Ответы:
В C ++ есть три разных типа символов:
char
signed char
unsigned char
Если вы используете типы символов для текста , используйте неквалифицированное char
:
'a'
или '0'
."abcde"
Он также работает как числовое значение, но не определено, рассматривается ли это значение как подписанное или без знака. Остерегайтесь сравнений персонажей из-за неравенства - хотя если вы ограничиваете себя ASCII (0-127), вы почти в безопасности.
Если вы используете типы символов в качестве чисел , используйте:
signed char
, который дает вам по крайней мере диапазон от -127 до 127. (Обычно от -128 до 127)unsigned char
, который дает вам по крайней мере диапазон от 0 до 255.«По крайней мере», потому что стандарт C ++ дает только минимальный диапазон значений, который должен охватывать каждый числовой тип. sizeof (char)
должен быть равен 1 (т. е. один байт), но теоретически байт может составлять, например, 32 бита. sizeof
все равно будет сообщать о его размере как ... это1
означает, что вы могли бы иметь sizeof (char) == sizeof (long) == 1
.
sizeof
потому что это не функция, а оператор. ИМХО, даже лучше, не использовать круглые скобки при определении размера переменной. sizeof *p
или sizeof (int)
. Это быстро дает понять, относится ли это к типу или переменной. Кроме того, после него необходимо ставить круглые скобки return
. Это не функция.
char
: это тип символьных литералов, подобных 'a'
или '0'
." верно в C ++, но не в C. В C 'a'
есть int
.
Это зависит от реализации, так как стандарт 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)
возвращаемый 1
. Вы можете получить количество бит в символе с помощью CHAR_BIT
in limits.h
. Однако сегодня существует немного платформ, где это будет нечто иное, чем 8
.
Существует резюме хорошего этого вопроса здесь .
Как уже упоминалось с тех пор, как я это опубликовал, лучше использовать, int8_t
и uint8_t
если вы действительно хотите представлять маленькие целые числа.
CHAR_BIT
Стандарт должен быть не менее 8 бит.
Поскольку я чувствую, что это действительно необходимо, я просто хочу изложить некоторые правила C и C ++ (они одинаковы в этом отношении). Во- первых, все биты от unsigned 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;
Из этого также следует, что преобразование - это не просто усечение битов более высокого порядка. Счастливым событием для дополнения двоих является то, что это просто усечение, но то же самое не обязательно верно для других представлений знака.
UCHAR_MAX
?
(unsigned type)-1
это какая-то идиома. ~0
нет.
int x = 1234
и char *y = &x
. Двоичное представление 1234
есть 00000000 00000000 00000100 11010010
. Моя машина имеет прямой порядок байтов, поэтому она переворачивает ее и сохраняет в памяти 11010010 00000100 00000000 00000000
LSB. Теперь основная часть. если я использую printf("%d" , *p)
. printf
прочтете первые байты 11010010
только выход , -46
но 11010010
это 210
так , почему же распечатать -46
. Я действительно смущен, я думаю, что какой-то символ для целочисленного продвижения делает что-то, но я не знаю.
Как например использование неподписанного символа :
unsigned char
часто используется в компьютерной графике, которая очень часто (хотя и не всегда) назначает один байт для каждого компонента цвета. Обычно цвет RGB (или RGBA) представлен в виде 24 (или 32) битов, каждый из которых представляет собой unsigned char
. Поскольку unsigned char
значения попадают в диапазон [0,255], значения обычно интерпретируются как:
Таким образом, вы получите красный RGB как (255,0,0) -> (100% красный, 0% зеленый, 0% синий).
Почему бы не использовать signed char
? Арифметика и сдвиг бит становится проблематичным. Как уже объяснялось, signed char
диапазон a существенно смещен на -128. Очень простой и наивный (в основном неиспользуемый) метод преобразования RGB в оттенки серого заключается в усреднении всех трех цветовых компонентов, но это приводит к проблемам, когда значения цветовых компонентов являются отрицательными. Красный (255, 0, 0) составляет в среднем (85, 85, 85) при использовании unsigned char
арифметики. Однако, если бы значения были signed char
s (127, -128, -128), мы бы получили (-99, -99, -99), что будет (29, 29, 29) в нашем unsigned char
пространстве, что неверно ,
Если вы хотите использовать символ в виде небольшого целого числа, самый безопасный способ сделать это с int8_t
и uint8_t
типов.
int8_t
а не uint8_t
являются обязательными и не определены на архитектурах , где размер байт не ровно 8 бит. С другой стороны , signed char
и unsigned char
всегда доступны и гарантированно трюма не менее 8 бит. Это может быть общий путь, но не самый безопасный .
signed char
и unsigned char
? Или вы бы порекомендовали лучшую "более безопасную" альтернативу в этом конкретном случае? Например придерживаться «настоящих» целочисленных типов signed int
и unsigned int
вместо этого по какой-то причине?
signed char
и unsigned char
является переносимым для всех соответствующих реализаций и сэкономит место на диске, но может привести к некоторому увеличению размера кода. В некоторых случаях можно было бы сэкономить больше места для хранения, сохраняя небольшие значения в битовых полях или отдельные биты обычных целочисленных типов. Нет абсолютного ответа на этот вопрос, уместность этого подхода зависит от конкретного случая под рукой. И этот ответ никак не касается вопроса.
char
и unsigned char
не гарантируется, что они будут 8-битными типами на всех платформах - они гарантированно будут 8-битными или больше. Некоторые платформы имеют 9-битные, 32-битные или 64-битные байты . Однако наиболее распространенные на сегодняшний день платформы (Windows, Mac, Linux x86 и т. Д.) Имеют 8-битные байты.
signed char
имеет диапазон от -128 до 127; unsigned char
имеет диапазон от 0 до 255.
char
будет эквивалентен знаковому или неподписанному символу, в зависимости от компилятора, но это отдельный тип.
Если вы используете строки в стиле C, просто используйте char
. Если вам нужно использовать символы для арифметики (довольно редко), укажите для подписи явно или без знака для переносимости.
An unsigned char
является байтовым значением без знака (от 0 до 255). Вы можете думать о том, char
чтобы быть «персонажем», но это действительно числовое значение. Регулярное число char
подписано, поэтому у вас есть 128 значений, и эти значения отображаются на символы с использованием кодировки ASCII. Но в любом случае то, что вы храните в памяти, является байтовым значением.
С точки зрения прямых значений обычный символ используется , когда значения , как известно, между CHAR_MIN
и в CHAR_MAX
то время как символ без знака обеспечивает двойную диапазон от положительного конца. Например, если CHAR_BIT
равно 8, диапазон регулярных значений char
гарантированно будет только [0, 127] (потому что он может быть подписан или без знака), а unsigned char
будет [0, 255] и signed char
будет [-127, 127].
С точки зрения того, для чего он используется, стандарты позволяют напрямую преобразовывать объекты POD (простые старые данные) в массив без знака. Это позволяет вам исследовать представление и битовые структуры объекта. Та же самая гарантия безопасного типа наказания не существует для символа или подписанного символа.
unsigned char
, а не массива конкретно, и любое «преобразование» только формально определяются копирование от объекта к реальному, объявленному массиву из unsigned char
& затем проверок последних. Не ясно, может ли OR быть интерпретировано как такой массив напрямую, с учетом арифметики указателей, которое это повлечет за собой, т. Е. Будет ли «последовательность» ==
«массивом» в этом использовании. Есть основная проблема № 1701, открытая в надежде получить разъяснения. К счастью, эта неоднозначность действительно беспокоит меня в последнее время.
unsigned char
из ИЛИ, а затем продолжить использовать ++ptr
оттуда для чтения каждого его байта ... но AFAICT, он не определен как разрешенный, поэтому мы Осталось сделать вывод, что «вероятно, все в порядке» из множества других отрывков (и во многих отношениях, просто существования memcpy
) в Стандарте, сродни мозаике. Что не идеально. Ну, возможно, формулировка улучшится в конце концов. Вот проблема CWG, о которой я упоминал, но не хватало места для ссылки - open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#1701
unsigned char
это сердце всей хитрости. Почти во всех компиляторах для платформы ALL это unsigned char
просто байт и целое число без знака (обычно) 8 битов, которое можно рассматривать как маленькое целое число или пакет битов.
В зависимости, как сказал кто-то еще, стандарт не определяет знак символа. поэтому у вас есть 3 различных char
типов: char
, signed char
, unsigned char
.
Если вам нравится , используя различные типы длины конкретного и знаковости, вы , вероятно , лучше с uint8_t
, int8_t
, uint16_t
и т.д. , просто потому , что они делают именно то , что они говорят.
Некоторые погуглили это , где люди обсуждали это.
Неподписанный символ - это в основном один байт. Таким образом, вы могли бы использовать это, если вам нужен один байт данных (например, может быть, вы хотите использовать его для включения и выключения флагов, передаваемых в функцию, как это часто делается в Windows API).
Беззнаковый символ использует бит, зарезервированный для знака обычного символа, в качестве другого числа. Это изменяет диапазон на [0 - 255], а не на [-128 - 127].
Обычно неподписанные символы используются, когда вы не хотите знак. Это будет иметь значение при выполнении таких вещей, как смещение битов (смещение расширяет знак) и другие вещи при работе с символом как байтом, а не с использованием его в качестве числа.
цитата из книги "C программирования laugage":
Квалификатор signed
or unsigned
может применяться к char или любому целому числу. числа без знака всегда положительны или равны нулю и подчиняются законам арифметики по модулю 2 ^ n, где n - количество бит в типе. Так, например, если символы состоят из 8 битов, переменные без знака имеют значения от 0 до 255, в то время как знаковые символы имеют значения от -128 до 127 (в машине дополнения до двух). Независимо от того, являются ли обычные символы со знаком или без знака, это машина -зависимые, но печатные символы всегда положительны.
signed char
и unsigned char
оба представляют 1 байт, но у них разные диапазоны.
Type | range
-------------------------------
signed char | -128 to +127
unsigned char | 0 to 255
В signed char
случае, если мы рассмотрим char letter = 'A'
, «A» представляет двоичный код 65 в ASCII/Unicode
, если 65 может быть сохранен, -65 также может быть сохранен. Там нет отрицательных двоичных значений, ASCII/Unicode
поэтому не нужно беспокоиться об отрицательных значениях.
пример
#include <stdio.h>
int main()
{
signed char char1 = 255;
signed char char2 = -128;
unsigned char char3 = 255;
unsigned char char4 = -128;
printf("Signed char(255) : %d\n",char1);
printf("Unsigned char(255) : %d\n",char3);
printf("\nSigned char(-128) : %d\n",char2);
printf("Unsigned char(-128) : %d\n",char4);
return 0;
}
Вывод -:
Signed char(255) : -1
Unsigned char(255) : 255
Signed char(-128) : -128
Unsigned char(-128) : 128