文字の最初の文字と16進定数を比較してデータの種類を判別しようとしています。しかし、それが失敗するたびに。誰も下の比較が常に失敗する理由を説明することはできますか?比較は常にcharと定数で失敗します
char charray[] = {0xAA, 0x00, 0x02};
char ch = charray[0];
if (0xAA == ch)
{
printf("Equal\n");
}
文字の最初の文字と16進定数を比較してデータの種類を判別しようとしています。しかし、それが失敗するたびに。誰も下の比較が常に失敗する理由を説明することはできますか?比較は常にcharと定数で失敗します
char charray[] = {0xAA, 0x00, 0x02};
char ch = charray[0];
if (0xAA == ch)
{
printf("Equal\n");
}
問題はここにある:
char charray[] = {0xAA, 0x00, 0x02};
char型は、いくつかのシステムで、それはsigned char
と等価になることを意味し、実装定義の符合を持っています。 signed char
は0x7Fまでの値しか格納できず、MSBは符号ビットとして扱われます。これはあなたの場合に起こります。0xAA
は符号付きの値-86
に変換されます(実装定義によってどの値が得られるか、私は2の補数と仮定しています)。
は昇格されて符号が保存されるため、符号は0xAA == ch
に保存されます。あなたが実際に0xAA == -86
を偽と比較することを意味します。
このようなバグを回避するには、バイトレベルで算術演算を行う場合は常にuint8_t
を使用してください。
0xAA
リテラルint
です。 char
は、システム上で署名付きまたは署名なしのいずれかになります。 Cの標準でもどちらかが可能です。 0xAA == ch
で
、ch
はint
型に昇格し、比較が(signed char
としてchar
又はunsigned char
の挙動はCで実装依存である)char
がsigned char
であると仮定すると0
if (0xAA == ch)
に評価され、 は==
の式と32ビットシステムでは実際に比較してに昇格されます。
if (0xAA == 0xFFFFFFAA)
これはfalseです。符号拡張を防ぐために
一つの方法は、unsigned char
に右オペランドをキャストすることです:
if (0xAA == (unsigned char) ch)
しかし、最高のは、あなたがあなたの配列を宣言する際に、単純にunsigned char
を使用することです。
いいえ、彼は実際に '0xAA == -86'を比較しています。明示的なプロモーションが特定のシステムでどのように出るかに応じて、必ずしも '0xAA == 0xFFFFFFAA'と同じではありません。 – Lundin
@ Lundinあなたが気楽になりたいのであれば、実際には0xAA ==(signed char)0xAAを比較しています。 – ouah
私のポイントは:左側のオペランド(intリテラル)が 'int'である限り、charは整数昇格(整数昇格規則)を経て署名されたままになります。しかし、リテラルが符号なしタイプの場合、平衡(通常の算術変換)もあり、右オペランドも符号なしタイプに変換されます。その場合、実際には '0xFFFFFFAAu'に等しくなります。しかし、この具体例では起こりません。 – Lundin