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

Что означает подписка на char?

Учитывая, что подписанные и unsigned ints используют одни и те же регистры и т.д. и просто интерпретируют битовые шаблоны по-разному, а символы C - это просто 8-битные ints, какова разница между подписанными и unsigned символами в C? Я понимаю, что подписанность char определяется реализацией, и я просто не могу понять, как это могло бы иметь значение, по крайней мере, когда char используется для хранения строк вместо того, чтобы выполнять математику.

4b9b3361

Ответ 1

Это не повлияет на строки. Но в C вы можете использовать char для выполнения математики, когда это будет иметь значение.

Фактически, при работе в средах с ограниченной памятью, таких как внедренные 8-разрядные приложения, char часто используется для выполнения математики, а затем это имеет большое значение. Это связано с тем, что по умолчанию в C не существует типа byte.

Ответ 2

В терминах значений, которые они представляют:

unsigned char:

  • охватывает диапазон значений 0..255 (00000000..11111111)
  • значения переполняются вокруг нижнего края как:

    0 - 1 = 255 (00000000 - 00000001 = 11111111)

  • значения переполняются вокруг большого края как:

    255 + 1 = 0 (11111111 + 00000001 = 00000000)

  • побитовый оператор сдвига вправо (>>) выполняет логический сдвиг:

    10000000 >> 1 = 01000000 (128 / 2 = 64)

подписан char:

  • охватывает диапазон значений -128..127 (10000000..01111111)
  • значения переполняются вокруг нижнего края как:

    -128 - 1 = 127 (10000000 - 00000001 = 01111111)

  • значения переполняются вокруг большого края как:

    127 + 1 = -128 (01111111 + 00000001 = 10000000)

  • оператор побитового сдвига вправо (>>) выполняет арифметический сдвиг:

    10000000 >> 1 = 11000000 (-128 / 2 = -64)

Я включил двоичные представления, чтобы показать, что поведение обертывания значений является чистой, последовательной двоичной арифметикой и не имеет ничего общего с char, подписанным/неподписанным (ожидается для сдвигов вправо).

Обновление

Некоторое поведение, специфичное для реализации, упомянутое в комментариях:

Ответ 3

#include <stdio.h>

int main(int argc, char** argv)
{
    char a = 'A';
    char b = 0xFF;
    signed char sa = 'A';
    signed char sb = 0xFF;
    unsigned char ua = 'A';
    unsigned char ub = 0xFF;
    printf("a > b: %s\n", a > b ? "true" : "false");
    printf("sa > sb: %s\n", sa > sb ? "true" : "false");
    printf("ua > ub: %s\n", ua > ub ? "true" : "false");
    return 0;
}


[root]# ./a.out
a > b: true
sa > sb: true
ua > ub: false

Это важно при сортировке строк.

Ответ 4

Есть пара отличий. Самое главное, если вы переполнили допустимый диапазон char, присвоив ему слишком большое или маленькое целое число, а char будет подписано, результирующее значение будет реализовано или даже некоторый сигнал (в C) может быть поднят, так как для всех подписанных типов. Сравните это с тем случаем, когда вы присваиваете слишком большое или маленькое значение без знака char: значение обтекает, вы получите точно определенную семантику. Например, присваивая значение -1 неподписанному char, вы получите UCHAR_MAX. Поэтому всякий раз, когда у вас есть байт, как в количестве от 0 до 2 ^ CHAR_BIT, вы должны действительно использовать unsigned char для его сохранения.

Знак также имеет значение при переходе к vararg-функциям:

char c = getSomeCharacter(); // returns 0..255
printf("%d\n", c);

Предположим, что значение, присвоенное c, будет слишком большим для представления char, и машина использует два дополнения. Многие реализации ведут себя так, что вы присваиваете слишком большое значение char, поскольку бит-шаблон не изменится. Если int будет способен представлять все значения char (что для большинства реализаций), то char продвигается до int перед передачей printf. Итак, значение переданного будет отрицательным. Продвижение к int сохранит этот знак. Таким образом, вы получите отрицательный результат. Однако, если char не имеет знака, то значение не указано, и продвижение к int даст положительный int. Вы можете использовать unsigned char, тогда вы получите точно определенное поведение как для назначения переменной, так и для передачи printf, которая затем напечатает что-то положительное.

Обратите внимание, что char, без знака и подписанные char все имеют ширину не менее 8 бит. Нет требования, чтобы char составлял ровно 8 бит. Однако для большинства систем это правда, но для некоторых вы обнаружите, что они используют 32-битные символы. Байт в C и С++ определяется как размер char, поэтому байт в C также не всегда равен 8 бит.

Другое отличие состоит в том, что в C неподписанный char не должен иметь битов заполнения. То есть, если вы обнаружите, что CHAR_BIT равно 8, значения без знака char должны находиться в диапазоне от 0.. 2 ^ CHAR_BIT-1. То же самое верно для char, если оно не указано. Для подписанного char вы не можете предполагать ничего о диапазоне значений, даже если вы знаете, как ваш компилятор реализует знак (два дополнения или другие варианты), в нем могут быть неиспользуемые биты заполнения. В С++ нет битов заполнения для всех трех типов символов.

Ответ 5

"Что означает, что для char должна быть подписана?"

Традиционно набор символов ASCII состоит из 7-битных кодировок символов. (В отличие от 8-битного EBCIDIC.)

Когда язык C был разработан и реализован, это было серьезной проблемой. (По различным причинам, таким как передача данных через последовательные модемные устройства.) Дополнительный бит использует как четность.

Символ "подписанный символ" оказывается идеальным для этого представления.

Двоичные данные, OTOH, просто принимают значение каждого 8-битного "куска" данных, поэтому знак не нужен.

Ответ 6

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

  • преобразование в более крупный int
  • функции сравнения

Отвратительная вещь: они не укусят вас, если все ваши строковые данные 7-битные. Тем не менее, он promises будет бесконечным источником неясных ошибок, если вы пытаетесь сделать вашу программу на C/С++ чистым.

Ответ 7

Подпись работает практически так же, как и в других интегральных типах. Как вы отметили, символы - это всего лишь однобайтовые целые числа. (Не обязательно 8-бит, хотя! Разница: байт может быть больше 8 бит на некоторых платформах, а char привязаны к байтам из-за определений char и sizeof(char). CHAR_BIT macro, определенный в <limits.h> или С++ <climits>, расскажет вам, сколько бит находится в char.).

Для чего вам нужен символ со знаком: в C и С++ нет стандартного типа byte. Для компилятора char - это байты и наоборот, и он не различает их. Иногда, однако, вы хотите: иногда вы хотите, чтобы char был однобайтовым числом, и в тех случаях (особенно, насколько маленький диапазон может содержать байты), вы также обычно заботитесь о том, подписано ли число или не. Я лично использовал подпись (или unsignedness), чтобы сказать, что определенный char является (числовым) "байтом", а не символом, и что он будет использоваться численно. Без указанной подписи, что char действительно является символом и предназначен для использования в качестве текста.

Раньше я это делал. Теперь более новые версии C и С++ имеют (u?)int_least8_t (в настоящее время typedef'd в <stdint.h> или <cstdint>)), которые более явно являются числовыми (хотя обычно они типично будут typedefs для подписанных и неподписанных типов char).

Ответ 8

Единственная ситуация, я могу себе представить, что это проблема, если вы решили делать математику по символам. Это совершенно законно, чтобы написать следующий код.

char a = (char)42;
char b = (char)120;
char c = a + b;

В зависимости от подписи char c может быть одним из двух значений. Если char являются неподписанными, то c будет (char) 162. Если они подписаны, то это будет случай переполнения, так как максимальное значение для подписанного char равно 128. Я предполагаю, что большинство реализаций вернутся (char) - 32.

Ответ 9

Одна вещь о подписанных символах заключается в том, что вы можете проверить c >= '' (пробел) и убедиться, что это обычный печатный ascii char. Конечно, это не переносимо, поэтому не очень полезно.