Как представить отрицательные значения символов в шестнадцатеричном формате? - PullRequest
0 голосов
/ 11 июля 2011

Следующий код

char buffer[BSIZE];
...
if(buffer[0]==0xef)
...

Дает предупреждение компилятора "сравнение всегда ложно из-за ограниченного диапазона типа данных".Предупреждение исчезает, когда я изменяю чек на

if(buffer[0]==0xffffffef)

Это кажется очень нелогичным.Как правильно проверить char по определенному байтовому значению в шестнадцатеричном формате?(кроме как сделать его без знака)

Ответы [ 5 ]

6 голосов
/ 11 июля 2011

Что не так с:

if (buffer[0] == '\xef')

4 голосов
/ 11 июля 2011

Чтобы понять, почему buffer[0] == 0xef вызывает предупреждение, а buffer[0] == 0xffffffef нет, вам нужно точно понять, что происходит в этом выражении.

Во-первых, оператор == сравнивает значение двух выражений, а не базовое представление - 0xef - это число 239, и будет сравниваться только равное этому числу; аналогично 0xffffffef - это число 4294967279, и оно будет сравниваться только с ним.

Нет разницы между константами 0xef и 239 в C: оба имеют тип int и одно и то же значение. Если ваш char имеет диапазон от -128 до 127, то при оценке buffer[0] == 0xef значение buffer[0] повышается до int, что оставляет его значение без изменений. Поэтому он никогда не может сравниваться равным 0xef, поэтому предупреждение верно.

Однако - это потенциально разница между константами 0xffffffef и 4294967279; десятичные константы всегда подписаны, но шестнадцатеричная константа может быть без знака. В вашей системе он имеет тип без знака - вероятно, unsigned int (поскольку значение слишком велико для хранения в int, но достаточно мало для хранения в unsigned int). Когда вы оцениваете buffer[0] == 0xffffffef, buffer[0] повышается до unsigned int. Это оставляет любое положительное значение без изменений, но отрицательные значения преобразуются путем добавления к ним UINT_MAX + 1; с char, который имеет диапазон от -128 до 127, повышенные значения находятся в любом из диапазонов от 0 до 127 или от 4294967168 до 4294967295. 0xffffffef лежит в этом диапазоне, поэтому сравнение может вернуть true.


Если вы храните битовые комбинации, а не числа, то вам следует использовать unsigned char в первую очередь. В качестве альтернативы вы можете проверить битовую комбинацию объекта, указав на него указатель unsigned char *:

if (((unsigned char *)buffer)[0] == 0xef)

(Очевидно, это удобнее сделать, используя отдельную переменную типа unsigned char *).

Как говорит PaulR , вы также можете использовать buffer[0] == '\xef' - это работает, потому что '\xef' определена как константа int со значением, которое char объект с битовой комбинацией 0xef имел бы при преобразовании в Int; например. в системе дополнения 2s со знаковыми символами '\xef' является константой со значением -17.

3 голосов
/ 11 июля 2011

Это происходит потому, что содержимое buffer имеет тип char.Создание их unsigned char будет работать:

if ((unsigned char) (buffer[0]) == 0xef)
2 голосов
/ 11 июля 2011

Чтобы объяснить причину в явном виде: является ли char подписанным или неподписанным, определяется реализацией. Если ваш компилятор обрабатывает char как подписанный по умолчанию, тогда 0xef будет больше, чем наибольшее возможное signed char (что равно 127 или 0x7f), и поэтому ваше сравнение всегда будет ложным. Отсюда и предупреждение.

Возможные решения представлены другими ответами.

2 голосов
/ 11 июля 2011

Сделайте это так же, как с любым другим отрицательным числом:

if (buffer[0]== -0x6f)

Но обычно вы хотите использовать unsigned char в качестве типа данных:

unsigned char buffer[BSIZE];
...
if(buffer[0]==0xef)

Причины использования подписанного символа очень редки. Еще более редкими являются причины использования «char без спецификации знака», который может быть подписан или не подписан на разных платформах.

...