Как представить отрицательные значения символов в шестнадцатеричном формате?
Следующий код
char buffer[BSIZE];
...
if(buffer[0]==0xef)
...
Дает предупреждение компилятора "сравнение всегда ложно из-за ограниченного диапазона типов данных". Предупреждение исчезнет, когда я поменяю чек на
if(buffer[0]==0xffffffef)
Это кажется очень нелогичным. Как правильно проверить char
против конкретного значения байта в шестнадцатеричном? (кроме как сделать его без знака)
5 ответов
Чтобы понять почему 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.
Это происходит потому, что buffer
содержимое имеет тип char
, Делать их unsigned char
буду работать:
if ((unsigned char) (buffer[0]) == 0xef)
Четко изложить причину: char
является подписанным или неподписанным, определяется реализацией. Если ваш компилятор лечит char
как подписано по умолчанию тогда 0xef
будет больше, чем максимально возможный signed char
(что 127 или 0x7f
) и поэтому ваше сравнение всегда будет ложным. Отсюда и предупреждение.
Возможные решения предоставлены другими ответами.
Сделайте это так же, как с любым другим отрицательным числом:
if (buffer[0]== -0x6f)
Но обычно вы хотите использовать unsigned char в качестве типа данных:
unsigned char buffer[BSIZE];
...
if(buffer[0]==0xef)
Причины использовать подписанный символ очень редки. Еще более редкими являются причины использовать "char без спецификации знака", которые могут быть подписаны или не подписаны на разных платформах.