4

このCコードを考えてみましょう。

#include "stdio.h"

int main(void) {

    int count = 5;
    unsigned int i;

    for (i = count; i > -1; i--) {
        printf("%d\n", i);
    }
    return 0;
}

私の観察/質問:ループは決して実行されません。しかし、iのデータ型をunsigned intからintに変更すると、すべてが期待どおりに機能します。

私は、符号なしintを、減算を続けようとすると「ラップアラウンド」する値と考えてきました。したがって、iがゼロで1を引くと、UINT_MAXにラップアラウンドします。そして、その値が負になることは決してないので、これは事実上無限ループになります。(そして、これは、比較をi>-1からi>= 0に変更したときに起こることです。)

ロジックのどこかに障害があります。iが符号なしの場合、ループが実行されることはなく、-1と比較しています。コンパイラが何らかの方法でそれを最適化するか、実行時の値が私が期待するものとは異なる動作をするかのどちらかです。

ループが実行されないのはなぜですか?

4

4 に答える 4

19

ではi > -1、-1がに変換さunsigned intれ、値はになりますUINT_MAXiはその値より大きくなることはないため、ループ本体は実行されません。

コンパイラを説得して、これについて警告することができる場合があります。条件付きコンテキストでのalways-trueまたはalways-false式の使用。しかし、それでもあなたが書いたとしても役に立たないi > -2ので、すべての混合符号の比較に対して警告を有効にできることもあるかもしれません。

Cでは、算術演算は常に等しいタイプのオペランドを使用して実行されることに注意してください。これには比較が含まれますが、IIRCはシフト演算子ではありません。この場合のように、オペランドのタイプが異なる場合、それらの少なくとも1つが同じタイプになるように変換されます。宛先タイプを決定するための規則は、6.3.1.1/2および6.3.1.8/1にあります。

于 2011-06-02T17:16:17.137 に答える
3

+「型対称」二項演算( 、*またはこの例では)で同じ幅の符号付きオペランドと符号なしオペランドを混在させると>、符号なし型が「勝ち」、演算は符号なしドメインで評価されます。つまり、符号付きオペランドは符号なし型に変換されます。

あなたの例では、整数定数のタイプsigned intは、ですiが、タイプはunsigned intです。オペランドの幅は同じであるため、この例i > -1では、と解釈されます。i > (unsigned) -1これは。と同等i > UINT_MAXです。これが、ループが実行されない理由です。

于 2011-06-02T17:17:42.840 に答える
0

符号なし数値と符号付き数値のどちらを扱っている場合でも、-1は常に0xffffffffとしてコンパイルされます。プロセッサには、符号付きと符号なしの両方の比較フラグがあります。その数を5と比較すると、符号付きフラグはそれを-1として扱い、小さいと言いますが、符号なしフラグはそれを大きい数として扱い、大きいと言います。その数値もUINT_MAXと同じであるため、すべての符号なし数値の比較はfalseになります。

于 2011-06-02T17:22:23.443 に答える
0

-1UINT_MAXは符号なしの比較になります。それよりも大きい数はないため、ループ条件が真になることはなく、ループに入ることがありません。

に変更するとi >= 0、期待どおりに機能するはずです。実際、この場合はおそらくunsignedを使用すべきではありません:-)

于 2011-06-02T17:17:53.313 に答える