★signedとunsignedの比較★


「符号あり(signed)」のデータと「符号無し(unsigned)」のデータを比較するとコンパイル時に警告が出ます。

例えば、次のプログラムをコンパイルしてみてください。

<sample program col037-01>

#include <stdio.h>

int main(void)
{
    int data1 = 10;

    unsigned int data2 = 15;

    if (data1 < data2) {
        printf("data2が大きい\n");
    }

    return 0;
}

<コンパイル結果>

warning C4018: '<': signed と unsigned の数値を比較しようとしました。

これは、

data1 < data2

が原因で発生している警告です。

ただ、実行してみると、

<実行結果>

data2が大きい
続行するには何かキーを押してください・・・

特に問題なく、動作するように見えますね。


では、数値を変えて実行してみましょう。

<sample program col037-02>

#include <stdio.h>

int main(void)
{
    int data1 = -1;

    unsigned int data2 = 15;

    if (data1 < data2) {
        printf("data2が大きい\n");
    }

    return 0;
}

<実行結果>

続行するには何かキーを押してください・・・

数値を見ると、data1の方が明らかに小さいにも関わらず、「data2が大きい」という結果は表示されていません。

これが警告の元となっている原因です。


暗黙の型変換


型変換については「キャスト」というコラムで説明済みです。

その中で「暗黙の型変換」について超適当に説明しました。

もう少し丁寧に説明しなおします。

整数と実数(小数)は2進数レベルで考えると、データの構造が異なります。

コンピュータは、データの構造が異なる数値の計算は出来ません。

単純な例ですが、

 15 + 2.8

は、そのままでは計算出来ないのです。

計算する時にはどちらかに形を合わせる必要がありますので、

  15を実数にする

  2.8を整数にする

のどちらかです。

2.8を整数にする(小数点以下切り捨て)と2になりますから、正しい計算結果ではなくなります。

ですから、この場合は15を実数にして計算するのです。

  15.0 + 2.8 = 17.8

この変換はどこにも表示されないまま「勝手に」行われますので、「暗黙の型変換」と言います。

この変換は「精度の高い方の型に合わせる」という決まりがあります。

精度の高い順に変数の型を書くと、

高 double

  float

  unsigned int

低 int

となります。

これを<sample program col037-02>に当てはめてみると、

int data1 = -1;

unsigned int data2 = 15;

この2つは型が異なるため、そのままでは計算出来ません。

精度が高いのは「unsigned int」の方ですから、data1は型変換されます。

data1には「−1」が入っていましたが、型変換されて「符号無し」になりました。

「−1」のビット列を32ビットで表現すると、

  1111 1111 1111 1111 1111 1111 1111 1111

です。

このビット列は「符号無し」の場合、

  4294967295(10進数)

です。

と言う事は、

if (data1 < data2) {
    printf("data2が大きい\n");
}

このif文は

  4294967295 < 15

と判断されるため、成立しません。


「signed」と「unsigned」を比較するとこのように危険なバグが発生する可能性があるのです。

プログラマーのミスでなければ、最初からどちらかに合わせてプログラムを組むべきです。


ブラウザの戻るボタンで戻ってください。