2015-12-22 13 views
7

文字の最初の文字と16進定数を比較してデータの種類を判別しようとしています。しかし、それが失敗するたびに。誰も下の比較が常に失敗する理由を説明することはできますか?比較は常に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と等価になることを意味し、実装定義の符合を持っています。 signed charは0x7Fまでの値しか格納できず、MSBは符号ビットとして扱われます。これはあなたの場合に起こります。0xAAは符号付きの値-86に変換されます(実装定義によってどの値が得られるか、私は2の補数と仮定しています)。

は昇格されて符号が保存されるため、符号は0xAA == chに保存されます。あなたが実際に0xAA == -86を偽と比較することを意味します。

このようなバグを回避するには、バイトレベルで算術演算を行う場合は常にuint8_tを使用してください。

1

0xAAリテラルintです。 charは、システム上で署名付きまたは署名なしのいずれかになります。 Cの標準でもどちらかが可能です。 0xAA == ch

chint型に昇格し、比較が(signed charとしてchar又はunsigned charの挙動はCで実装依存である)charsigned charであると仮定すると0

1
if (0xAA == ch) 

に評価され、 は==の式と32ビットシステムでは実際に比較してに昇格されます。

if (0xAA == 0xFFFFFFAA) 

これはfalseです。符号拡張を防ぐために

一つの方法は、unsigned charに右オペランドをキャストすることです:

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

しかし、最高のは、あなたがあなたの配列を宣言する際に、単純にunsigned charを使用することです。

+0

いいえ、彼は実際に '0xAA == -86'を比較しています。明示的なプロモーションが特定のシステムでどのように出るかに応じて、必ずしも '0xAA == 0xFFFFFFAA'と同じではありません。 – Lundin

+0

@ Lundinあなたが気楽になりたいのであれば、実際には0xAA ==(signed char)0xAAを比較しています。 – ouah

+0

私のポイントは:左側のオペランド(intリテラル)が 'int'である限り、charは整数昇格(整数昇格規則)を経て署名されたままになります。しかし、リテラルが符号なしタイプの場合、平衡(通常の算術変換)もあり、右オペランドも符号なしタイプに変換されます。その場合、実際には '0xFFFFFFAAu'に等しくなります。しかし、この具体例では起こりません。 – Lundin

関連する問題