【C/C++】C4018「signed と unsigned の数値を比較しようとしました」の対処法

C/C++

C/C++のプログラムのコンパイルは通るのに警告が表示されるといったことはありませんか?

「signed と unsigned の数値を比較しようとしました」というのもコンパイルは通るけど警告が出るものの一つです。

なぜこのような警告が表示されてしまうのか解説していきます。

C4018「signed と unsigned の数値を比較しようとしました」が発生する原因と解決方法

この警告は、扱える数値の範囲が異なるsigned変数とunsigned変数の2つを比較した際に発生します。

#include
int main() {
    unsigned int uc = -100;
    int c = 0;

    if (uc < c) {
        printf("cのほうが大きい");
    }
    else {
        printf("cの方が小さい");
    };
}
cのほうが小さい

明らかに-100は0より小さいにもかかわらず実行結果がおかしくなっています。

この警告を解消したい場合は変数の型を統一するようにしましょう。

このような挙動になってしまう原因

C/C++には符号なしと符号ありの2種類があることは知っていますか?

符号ありと符号なしでは扱える数値の範囲が異なっており、int型の場合だと以下のようになります。

int型符号あり(signed)符号なし(unsighned)
最小値-2,147,483,6480
最大値2,147,483,6474,294,967,295

範囲はこの様になっており、範囲外の値を代入・使用しようとするとオーバーフロー・アンダーフローが発生します。

オーバーフローとは

    コンピュータの演算において数値型が表現可能な値の上限を超えること、およびそれによって発生したエラー。「桁あふれ」ともいう。対義語はアンダーフロー。

    出典:Wikipedia – オーバーフロー

    以下のサンプルコードを見てください。

    int main() {
        int a = -100;
        unsigned int b = a;
        std::cout << a << std::endl;
        std::cout << b << std::endl;
    }
    -100
    4294967196

    一見すると普通のコードに見えるかもしれませんが、変数a(-100)をマイナスの値を扱えない符号なしint型変数bに代入した影響でアンダーフローが発生しています。

    アンダーフローの影響で数値がおかしくなってしまい、その状態で比較すると条件分岐おかしくなってしまうために「signed と unsigned の数値を比較しようとしました」という警告が表示されるのです。

    気づきにくいバグになりやすいので、C4018警告が表示された場合は気付き次第すぐに修正するようにしましょう。

    Acceliv