2015-12-22 3 views
7

Я пытаюсь сравнить первый символ строки и шестнадцатеричную константу, чтобы определить тип данных. Но каждый раз он терпит неудачу. Может ли кто-нибудь объяснить, почему ниже сравнение всегда терпит неудачу.Сравнение всегда терпит неудачу с char и константой

char charray[] = {0xAA, 0x00, 0x02}; 
char ch = charray[0]; 
if (0xAA == ch) 
{ 
    printf("Equal\n"); 
} 

ответ

8

Проблемы здесь:

char charray[] = {0xAA, 0x00, 0x02}; 

Тип CHAR имеет определенную реализацию знаковости, а это означает, что в некоторых системах это будет эквивалентно signed char. A signed char может хранить только значения до 0x7F, и MSB будет обрабатываться как знаковый бит. Это то, что происходит в вашем случае, 0xAA преобразуется в значение со знаком -86 (оно определяется реализацией, какое значение оно получает, я предполагаю дополнение двух).

Знак затем сохраняется в выражении 0xAA == ch, так как ch затем подлежит произведению типа int и знак сохраняется. Это означает, что вы фактически будете сравнивать 0xAA == -86, что является ложным.

Чтобы избежать таких ошибок, всегда используйте uint8_t при выполнении любой формы арифметики на уровне байта.

1

0xAA является int буквальным. char может быть либо подписанным, либо без знака в вашей системе. Стандарт C позволяет либо.

В 0xAA == ch, то ch способствует к int типа, и сравнение имеет значение 0.

1
if (0xAA == ch) 

Если предположить, что это charsigned char (поведение char, как signed char или unsigned char зависит от реализации в C), char - int в выражении == и в 32-разрядной системе, которую вы фактически сравниваете:

if (0xAA == 0xFFFFFFAA) 

, что является ложным.

Один из способов предотвратить знак-расширение является приведение правого операнда unsigned char:

if (0xAA == (unsigned char) ch) 

Но лучше просто использовать unsigned char, когда вы объявить массив.

+0

Нет, он фактически сравнивает '0xAA == -86'. Не обязательно то же самое, что и '0xAA == 0xFFFFFFAA', в зависимости от того, как неявные рекламные акции оказываются в конкретной системе. – Lundin

+0

@ Lundin, если вы хотите быть придирчивым, он фактически сравнивает '0xAA == (signed char) 0xAA', который даже отличается, поскольку преобразование определяется реализацией. – ouah

+0

Моей точкой является то, что левый операнд (int literal) является «int», тогда char будет проходить только целую рекламу (целое правило продвижения) и оставаться подписанным. Но если литерал был неподписанным типом, также была бы балансировка (обычные арифметические преобразования), и правый операнд также преобразуется в неподписанный тип. В этом случае вы на самом деле оказываетесь равным «0xFFFFFFAAu». Но этого не происходит в этом конкретном примере. – Lundin

Смежные вопросы