Что такое беззнаковый символ?

Для чего используется unsigned char в C / C++? Чем он отличается от обычного char?

Стоит ли изучать PHP в 2026-2027 годах?
Стоит ли изучать PHP в 2026-2027 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
496
0
613 275
17
Перейти к ответу Данный вопрос помечен как решенный

Ответы 17

Это зависит от реализации, поскольку стандарт 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 в limits.h. Однако сегодня есть несколько платформ, на которых это будет что-то другое, кроме 8.

Есть хорошее резюме этой проблемы здесь.

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

знаковый символ имеет минимальный диапазон от -127 до 127, а не от -128 до 127

12431234123412341234123 28.01.2017 09:40

@ 12431234123412341234123: Технически верно, поскольку стандарт C определяет от -127 до 127 как минимальный диапазон. Я призываю вас найти платформу, которая не использует арифметику с дополнением до двух. Практически на каждой современной платформе фактический диапазон подписанных символов будет от -128 до 127.

Todd Gamblin 06.02.2017 10:55

CHAR_BIT должен быть не менее 8 бит по стандарту.

martinkunev 12.03.2019 19:31

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

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

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

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

Не очень хорошая идея: int8_t и uint8_t являются необязательными и не определены в архитектурах, где размер байта не равен 8 битам. И наоборот, signed char и unsigned char всегда доступны и гарантированно содержат не менее 8 бит. Это может быть способ общий, но не самый безопасный.

chqrlie 07.04.2015 01:44

Это комментарий, он не отвечает на вопрос.

Lundin 24.11.2017 11:30

@chqrlie Значит, самый безопасный способ представить небольшое целое число, если вы хотите сэкономить память, - это использовать signed char и unsigned char? Или вы порекомендуете более «безопасную» альтернативу в этом конкретном случае? Например, почему-то придерживаться "реальных" целочисленных типов signed int и unsigned int?

RobertS supports Monica Cellio 21.12.2019 15:17

@ RobertS-ReinstateMonica: Использование signed char и unsigned char переносимо для всех соответствующих реализаций и сэкономит место для хранения, но может вызвать некоторое увеличение размера кода. В некоторых случаях можно было бы сэкономить больше места для хранения, сохраняя небольшие значения в битовых полях или отдельных битах обычных целочисленных типов. На этот вопрос нет однозначного ответа, применимость этого подхода зависит от конкретного случая. И этот ответ в любом случае не отвечает на вопрос.

chqrlie 21.12.2019 18:08

Некоторые поисковые запросы нашли это, где люди обсуждали это.

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

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

«Обычный символ подписан»: нет, это зависит от реализации. И нет никакой гарантии, что диапазон значений беззнакового char составляет от 0 до 255: это по крайней мере, но он может быть шире.

Fabio says Reinstate Monica 20.06.2020 04:21

Не гарантируется, что char будет байтом.

qwr 08.07.2020 22:40

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

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

Собственно, чаще всего это будет [-128, 128].

RastaJedi 24.04.2016 05:20

Стандарты только формально определяют представление объекта как последовательностьunsigned char, а не множество конкретно, и любое «преобразование» только формально определяется копирование из объекта в реальный, объявленный множествоunsigned char, а затем проверяет последний. Неясно, может ли OR быть напрямую переинтерпретировано как такой массив с учетом арифметики указателя, то есть, будет ли «последовательность» == «массивом» в этом использовании. В надежде прояснить основной вопрос №1701 был открыт. К счастью, эта двусмысленность в последнее время меня действительно беспокоит.

underscore_d 30.08.2016 15:49

@RastaJedi Нет, не пойдет. Не может. Диапазон -128 ... + 128 физически невозможно представить с помощью 8 бит. Эта ширина поддерживает только 2 ^ 8 == 256 дискретных значений, но -128 ... + 128 = 2 * 128 + 1 для 0 = 257. Представление величины знака допускает -127 ... + 127, но имеет 2 (биполярное) нули. Представление с дополнением до двух поддерживает один ноль, но составляет диапазон, имея еще одно значение на отрицательной стороне; допускает -128 ... + 127. (И так для обоих с большей разрядностью.)

underscore_d 30.08.2016 15:52

Что касается моего 2-го комментария, разумно, чтобы предполагать, мы могли взять указатель на 1-й unsigned char OR, а затем продолжить использование ++ptr оттуда, чтобы прочитать каждый его байт ... но AFAICT, он конкретно не определен как разрешенный, поэтому мы Осталось сделать вывод, что это "наверное хорошо" из множества других отрывков (и во многом из простого существования memcpy) в Стандарте, что сродни мозаике. Что не идеально. Что ж, может быть, формулировка со временем улучшится. Вот проблема CWG, о которой я упоминал, но не хватало места для ссылки - open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#1701

underscore_d 30.08.2016 15:59

@underscore_d извините, это была опечатка. [-128, 127] - вот что я хотел напечатать: p. Да, я знаю о двойных нулях («положительный» и «отрицательный» ноль) со знаком / величиной. Я, должно быть, устал: p.

RastaJedi 31.08.2016 01:31

Если вам нравится использовать различные типы определенной длины и подписи, вам, вероятно, лучше использовать uint8_t, int8_t, uint16_t и т. д. Просто потому, что они делают именно то, что говорят.

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

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

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

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

Битовые уловки, также известные как бит-тидлинг или бит-хакинг, действительно вызывают привыкание ;-)

chqrlie 07.04.2015 01:48

Проблемы возникают из-за 0. Чтобы избежать зависимости от твидлинга, держитесь подальше от мелочей.

DragonLord 23.05.2016 21:12

Например, использование беззнаковый символ:

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 chars (127, -128, -128), мы бы получили (-99, -99, -99), что было бы (29, 29, 29) в нашем пространстве unsigned char, что является неверно.

Не гарантируется, что char и unsigned char будут 8-битными типами на всех платформах - они гарантированно будут 8-битными или больше. На некоторых платформах есть 9-битные, 32-битные или 64-битные байты. Однако наиболее распространенные сегодня платформы (Windows, Mac, Linux x86 и т. д.) Имеют 8-битные байты.

Ответ принят как подходящий

В C++ существует три типа символов отчетливый:

  • char
  • signed char
  • unsigned char

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

  • это тип символьных литералов, таких как 'a' или '0'.
  • это тип, который составляет строки C, например "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.

Для ясности, могли бы вы иметь 32-битные символы и 32-битные целые числа и иметь sizeof (int)! = Sizeof (char)? Я знаю, что в стандарте указано sizeof (char) == 1, но основывается ли относительный sizeof (int) на фактической разнице в размере или разнице в диапазоне?

Joseph Garvin 12.01.2009 02:21

Джозеф, sizeof дает размер объектного представления типа. если вы скажете 32-битное int, это сначала мало что скажет. скорее всего, вы имеете в виду представление объекта (это физический размер, включая все биты заполнения).

Johannes Schaub - litb 14.01.2009 09:26

в этом случае sizeof (int)! = sizeof (char) не может быть истинным, потому что char / unsigned / signed char используют все биты своего объектного представления для представления своих значений (так называемое представление значения)

Johannes Schaub - litb 14.01.2009 09:27

Гарантированный диапазон signed char составляет от -127 до 127, но, предполагая дополнение 2, вы получите от -128 до 127. И это довольно безопасное предположение.

Steve Jessop 16.05.2012 14:49

как получилось, что 1 байт может быть 32 бита?

pseudonym_127 16.05.2013 10:19

+1. Но в C++ есть четыре различных типа символов, wchar_t - один из них.

Eric Z 24.08.2013 13:19

@Fruny Я заметил, что вы написали sizeof () с пробелом между ними, не могли бы вы объяснить его использование? На данный момент я ищу ответ по этому поводу. Заранее спасибо.

Unheilig 12.01.2014 00:23

начиная с С ++ 11 у вас есть 6 различных типов: char, signed char, unsigned char, wchar_t, char16_t, char32_t.

marcinj 16.02.2014 13:53

@ pseudonym_127 хороший вопрос. Я думаю, это потому, что технически размер бита не указан (хотя обычно это 8 бит). Надеюсь, кто-нибудь еще сможет это проверить.

Celeritas 09.08.2014 11:41

@unheilig Обычно после sizeof ставится пробел, потому что это не функция, а оператор. Имхо даже лучший стиль - опускать круглые скобки при выборе размера переменной. sizeof *p или sizeof (int). Это позволяет быстро понять, применимо ли это к типу или переменной. Точно так же излишне ставить круглые скобки после return. Это не функция.

Patrick Schlüter 28.11.2014 15:00

«char: это тип символьных литералов, таких как 'a' или '0'». верно в C++, но не в C. В C 'a' является int.

chux - Reinstate Monica 10.05.2016 20:30

Просто из любопытства вы говорите, что «теоретически байт может быть, например, 32 бита», но на самом деле байт равен 8 битам. Что мне не хватает? Спасибо.

Brian 28.03.2018 17:13

«байт» в этом контексте относится к наименьшей адресуемой единице памяти. Стандарты C и C++ требуют, чтобы байт был не менее 8 бит, но они не указывают максимум. Практически на всех современных компьютерах общего назначения (включая все, что совместимо с последними версиями posix) байт составляет ровно 8 бит, но специализированные платформы DSP и ретро-системы могут иметь байты большего размера.

plugwash 01.03.2019 21:48

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

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

If the new type is unsigned, the value is converted by repeatedly adding or subtracting one more than the maximum value that can be represented in the new type until the value is in the range of the new type. (6.3.1.3p2 in a C99 draft)

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

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

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

unsigned char c = (unsigned char)-1;

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

Почему бы просто не использовать UCHAR_MAX?

Nicolás 05.01.2011 01:01

Потому что (unsigned type)-1 - это какая-то идиома. ~0 - нет.

Patrick Schlüter 28.11.2014 15:07

если у меня есть что-то вроде этого 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. Я действительно смущен, я думаю, что какое-то продвижение char в целочисленное что-то делает, но я не знаю.

Suraj Jain 17.08.2016 13:23

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

в то время как

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

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

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

unsigned char принимает только положительные значения: от 0 до 255, в то время как signed char принимает положительные и отрицательные значения: от -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

Не гарантируется, что char будет одним байтом, а signed char гарантированно будет содержать только диапазон [-127,127] (хотя почти все системы используют дополнение до двух и содержат не менее [-128,127])

qwr 08.07.2020 22:42

Другие вопросы по теме