7

私は次のCコードを持っています:

unsigned int a;
unsigned char b, c;
void test(void) {
    if (a < b)
        return;
    if (a < (b ? b : c))
        return;
}

(Microsoftclを使用して、MS SDK 7の-W3警告レベルから)コンパイルすると、2番目の比較で警告が表示されます:C4018、符号付き/符号なしの不一致。最初の比較では警告は出されません。

条件演算子に関するMSのドキュメントを確認しましたが、両方のオペランドが同じタイプの場合、結果は同じタイプになるため、最初の比較として機能するはずです。私は何かが足りないのですか?

UPD:でテストされ、gcc -Wall -Wextra -pedantic警告はまったく表示されませんでした。

4

3 に答える 3

7

これはおそらく算術変換ルールによるものです。まず、int(など)よりも小さい整数型の変換ランクはまたはunsigned charに昇格します。intunsigned int

結果が(直接)元の型の符号に依存するかどうかに依存しますが、その範囲:intは、すべての値を表すことができる限り、符号なし型にも使用されます。これは、主流のアーキテクチャの場合です。unsigned intintunsigned char

次に、両方のオペランドの変換ランクは同じになりますが、一方は符号なしであるため、もう一方のオペランドも符号なし型に変換されます。

意味的に、あなたの表現は読みます

a < (unsigned int)(int)b

a < (unsigned int)(b ? (int)b : (int)c)

コンパイラは、最初のケースでは問題が発生しないことに気付くほど賢いようですが、2番目のケースでは失敗します。

Steve Jessopのコメントは、これがどのように発生するかをうまく説明しています。

最初のケースでは、コンパイラは「オペランドタイプがunsigned intとである比較演算子がありunsigned charます。警告の必要はありません。次に、昇格を適用してから通常の変換を行います」と考えると思います。

2番目のケースでは、「オペランドの型がunsigned intand int(RHSの条件式の型として導出した)である比較演算子があります。これについては警告してください!」と考えます。

于 2012-10-11T11:06:20.563 に答える
3

if (a < b)疑似に等しいif (unsigned int < unsigned char)

式でchar型が使用される場合は常に、Cの汎整数拡張規則によって暗黙的に.に変換されますint。それが行われた後、あなたは持っています

if (unsigned int < int)

ランクは同じで符号が異なる2つの整数が式で使用される場合は常に、符号付きの整数が暗黙的に符号なしに変換されます。これは、通常の算術変換、別名バランシングによって決定されます。

したがって、最初の式はに変換されます

if (unsigned int < unsigned int)

何かが行われる前に。


2番目の式では、if (a < (b ? b : c))疑似に等しいものがあります

if (unsigned int < (unsigned char ? unsigned char : unsigned char))

整数プロモーションはすべての文字で実行されるため、暗黙的に次のように変換されます。

if (unsigned int < (int ? int : int))

次に、条件演算子の奇妙であいまいなルールにより、?:演算子の2番目と3番目の演算子は、通常の算術変換とバランスを取る必要があります。この場合、それらはすでに同じタイプであるため、何も起こりません。最終的には

if (unsigned int < int)

バランシングが再度行われ、結果は次のように評価されます。

if (unsigned int < unsigned int)


Microsoftでコンパイルすると

あなたがマイクロソフトでコンパイルするとき、すべての賭けはオフであり、彼らのコンパイラは標準に従うのが非常に貧弱です。奇妙で非論理的な警告を期待してください。

于 2012-10-11T11:11:50.487 に答える
1

ルールはCとC++で異なります。CをMSVCでコンパイルする場合、適切な標準を判断するのは難しい場合がありますが、幸い、この場合、C89とC99は同じです。

C89 3.3.15では:

2番目と3番目のオペランドの両方が算術型である場合、通常の算術変換が実行されてそれらが共通の型になり、結果はその型になります。

C99 6.5.15 / 5の場合:

2番目と3番目のオペランドの両方に算術型がある場合、通常の算術変換によって決定される結果の型は、それらがこれらの2つのオペランドに適用された場合に、結果の型になります。

C ++ 03 5.16 / 4の場合:

2番目と3番目のオペランドが左辺値であり、同じタイプの場合、結果はそのタイプであり、左辺値になります。

したがって、「両方のオペランドが同じタイプの場合、結果は同じタイプになるため、最初の比較として機能するはずです」と言うと、CではなくC++にのみ適用されます。Cでは、その比較のRHSはですint。C ++では、RHSはunsigned char予想どおりタイプの左辺値になります。

于 2012-10-11T11:40:10.277 に答える