Почему C/С++ ненавидят подпись char так много?
Почему C разрешает доступ к объекту с использованием "типа символа":
6.5 Выражения (C)
Объект должен иметь сохраненное значение, доступное только с помощью выражения lvalue, которое имеет один из следующих типов:
но С++ допускает char и без знака char?
3.10 Lvalues и rvalues (С++)
Если программа пытается получить доступ к сохраненному значению объекта через значение gl другого, чем одно из следующих типов, поведение undefined:
- a char или неподписанный char тип.
Еще одна часть подписанной char ненависти (цитата из стандарта С++):
3.9 Типы (С++)
Для любого объекта (кроме подобъекта базового класса) тривиально-скопируемого типа T, независимо от того, имеет ли объект правильное значение типа T, базовые байты, составляющие объект, могут быть скопированы в массив char или без знака char. Если содержимое массива char или без знака char будет скопировано обратно в объект, объект должен сохранить первоначальное значение.
И из стандарта C:
6.2.6 Представления типов (C)
Значения, хранящиеся в объектах без битового поля любого другого типа объекта, состоят из бит n × CHAR_BIT, где n - размер объекта этого типа, в байтах. Значение может быть скопировано в объект типа без знака char [n] (например, memcpy); результирующий набор байтов называется представлением объекта значения.
Я вижу много людей в stackoverflow, потому что unsigned char - единственный тип символа, который не имеет битов заполнения, но раздел C99 6.2.6.2. Целочисленные типы говорит
подписанный char, не должен иметь никаких добавочных битов
Итак, какова истинная причина этого?
Ответы
Ответ 1
Здесь я беру на себя мотивацию:
В системе без двоичного дополнения signed char
не подходит для доступа к представлению объекта. Это связано с тем, что есть два возможных представления signed char
, которые имеют одинаковое значение (+0 и -0) или одно представление, которое не имеет значения (представление ловушки). В любом случае это мешает вам делать наиболее значимые вещи, которые вы можете сделать с представлением объекта. Например, если у вас есть 16-разрядное целое число без знака 0x80ff
, один или другой байт, как signed char
, будет либо ловушкой, либо сравняться с 0.
Обратите внимание, что в такой реализации (не-двоичное дополнение) plain char
необходимо определить как неподписанный тип для доступа к представлениям объектов через char
для правильной работы. Хотя явного требования нет, я рассматриваю это как требование, вытекающее из других требований стандарта.
Ответ 2
Я думаю, что вы действительно задаетесь вопросом, почему signed char
дисквалифицирован из всех правил, позволяющих вводить t-tning в качестве специального случая. Честно говоря, я не знаю, тем более, что — насколько я могу судить; signed char
тоже не может быть дополнением:
[C++11: 3.9.1/1]:
[..] A char
, a signed char
и a unsigned char
занимают одинаковое количество хранения и имеют одинаковые требования к выравниванию (3.11); то есть они имеют одно и то же представление объекта. Для типов символов в представлении значения участвуют все биты представления объекта. [..]
Эмпирические данные свидетельствуют о том, что это не намного больше, чем соглашение:
-
char
рассматривается как байт ASCII;
-
unsigned char
рассматривается как байт с произвольным "двоичным" контентом; и
-
signed char
остается ветром на ветру.
Для меня это не кажется достаточным основанием для исключения из этих стандартных правил, но я честно не могу найти никаких доказательств обратного. Я собираюсь привести его к мягко необъяснимой странности в стандартной формулировке.
(Возможно, нам нужно задать список std-discussion
об этом.)
Ответ 3
Использование типа символа для проверки представлений объектов - это взломать. Тем не менее, это исторический, и для его размещения необходимо сделать какое-то жилье.
В основном, в языках программирования нам требуется сильная типизация. То, что есть float
, должно быть доступно как float
, а не как int
. Это имеет ряд преимуществ, включая сокращение человеческих ошибок и возможность различных оптимизаций.
Однако есть моменты, когда необходимо получить доступ или изменить байты объекта. В C это было сделано через типы символов. С++ продолжает эту традицию, но это немного улучшает ситуацию, устраняя использование signed char
для этих целей.
В идеале было бы лучше создать новый тип, скажем byte
, и разрешить доступ к байтам только для представления объектов только через этот тип, тем самым отделяя обычные типы символов только для использования в качестве обычных целых чисел/символов. Возможно, считалось, что существует слишком много существующего кода, использующего char
и unsigned char
для поддержки такого изменения. Тем не менее, я никогда не видел, чтобы signed char
использовался для доступа к представлению объекта, поэтому было бы безопасно его исключить.