Подтвердить что ты не робот

Почему стандарты C или С++ явно не определяют char как подписанные или неподписанные?

int main()
{
    char c = 0xff;
    bool b = 0xff == c;
    // Under most C/C++ compilers' default options, b is FALSE!!!
}

Ни в стандарте C, ни в С++ не указывается char как подписанный или неподписанный, он определяется реализацией.

Почему стандарт C/С++ явно не определяет char как подписанный или неподписанный для предотвращения опасных злоупотреблений, таких как приведенный выше код?

4b9b3361

Ответ 1

Исторические причины, в основном.

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

С другой стороны, набор символов EBCDIC имеет базовые символы с высоким набором бит (т.е. символы со значениями 128 или более); на платформах EBCDIC, char в значительной степени должно быть без знака.

ANSI C Обоснование (для стандарта 1989 года) не может многое сказать по этому вопросу; раздел 3.1.2.5 гласит:

Указаны три типа char: signed, plain и unsigned. plain char может быть представлен как подписанный, так и неподписанный, в зависимости от как и в предыдущей практике. Тип signed charбыло введено для создания однобайтового целочисленного типа со знаком на те системы, которые реализуют plain char как unsigned. По причинам симметрии, ключевое слово signed разрешено как часть имени типа другие интегральные типы.

Возвращаясь еще дальше, ранняя версия Справочное руководство C > от 1975 года гласит:

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

Это описание более специфично для реализации, чем то, что мы видим в последующих документах, но оно подтверждает, что char может быть либо подписано, либо без знака. В "других реализациях", на которых "исчезновение знака" исчезает, продвижение объекта char к int имело бы нулевое расширенное 8-битное представление, по существу рассматривая его как 8-разрядную неподписанную величину. (Язык еще не имел ключевое слово signed или unsigned.)

C непосредственным предшественником был язык под названием B. B - это беспринципный язык, поэтому вопрос о char, подписанный или неподписанный, не применялся. Для получения дополнительной информации о ранней истории C см. Позднюю историю Dennis Ritchie , теперь перемещен здесь.

Что касается того, что происходит в вашем коде (применяя современные правила C):

char c = 0xff;
bool b = 0xff == c;

Если plain char не имеет знака, тогда инициализация c устанавливает его в (char)0xff, который сравнивается с 0xff во второй строке. Но если plain char подписан, то 0xff (выражение типа int) преобразуется в char - но поскольку 0xff превышает CHAR_MAX (при условии CHAR_BIT==8), результат определяется реализацией, В большинстве реализаций результат -1. В сравнении 0xff == c оба операнда преобразуются в int, что делает его эквивалентным 0xff == -1 или 255 == -1, что, конечно, ложно.

Еще одна важная вещь: unsigned char, signed char и (plain) char - три разных типа. char имеет то же представление, что и unsigned char или signed char; это определение реализации, какое оно есть. (С другой стороны, signed int и int - это два имени для одного и того же типа; unsigned int - это отдельный тип. (За исключением того, что для добавления к легкомыслию это реализация определяет, было ли поле бит объявлено как plain int подписан или без знака.))

Да, все это немного беспорядок, и я уверен, что это было бы определено иначе, если бы C разрабатывались с нуля сегодня. Но каждая ревизия языка C должна была не ломать (слишком много) существующий код и в меньшей степени существующие реализации.

Ответ 2

char сначала предназначен для хранения символов, поэтому подписанный или без знака не важен. Важно то, как эффективно выполнять математику на char. Поэтому, в зависимости от системы, компилятор выберет наиболее подходящий

До ARMv4 у ARM не было встроенной поддержки для загрузки полусловов и подписанных байтов. Чтобы загрузить подписанный байт, вы должны были LDRB, а затем подписать расширение (LSL, а затем ASR). Это больно, поэтому char по умолчанию не имеет знака.

fooobar.com/info/9427/...