1. ホーム
  2. c

[解決済み】0 < -0x80000000 はなぜ?

2022-04-01 10:21:17

疑問点

以下のような簡単なプログラムがあります。

#include <stdio.h>

#define INT32_MIN        (-0x80000000)

int main(void) 
{
    long long bal = 0;

    if(bal < INT32_MIN )
    {
        printf("Failed!!!");
    }
    else
    {
        printf("Success!!!");
    }
    return 0;
}

条件 if(bal < INT32_MIN ) は常に真である。どうしてそんなことが可能なのでしょうか?

マクロを変更すると正常に動作します。

#define INT32_MIN        (-2147483648L)

どなたかご指摘ください。

解決方法を教えてください。

これはかなり微妙なところです。

プログラム中のすべての整数リテラルには型があります。どの型を持っているかは、6.4.4.1の表で規定されています。

Suffix      Decimal Constant    Octal or Hexadecimal Constant

none        int                 int
            long int            unsigned int
            long long int       long int
                                unsigned long int
                                long long int
                                unsigned long long int

リテラルな数値がデフォルトの int の型は、上の表で示されるように、次に大きな型を試します。つまり、通常の10進整数リテラルの場合、次のようになります。

  • 試す int
  • フィットしない場合は、以下をお試しください。 long
  • サイズが合わない場合は long long .

しかし、Hex リテラルの動作は異なります! のような符号付きの型にリテラルが収まらない場合、そのリテラルは int の場合、まず unsigned int より大きな型を試す前に 上の表の違いを見てください。

つまり、32ビットシステムでは、リテラルの 0x80000000unsigned int .

つまり、単項演算子 - 演算子は、符号付き整数をオーバーフローさせるときのように、実装で定義された動作をさせることなくリテラルに作用します。そのかわり、値 0x80000000 は正の値です。

bal < INT32_MIN は通常の算術変換を行い、その結果、式 0x80000000 から昇格します。 unsigned int から long long . 値 0x80000000 は保存され、0は0x80000000より小さいので、このような結果になりました。

で置き換えると、リテラルは 2147483648L は10進数表記なので、コンパイラは unsigned int の中に収めようとします。 long . また、Lサフィックスは long 可能であれば . 6.4.4.1の表を読み進めると、Lサフィックスにも同様のルールがあります。 long 32ビットの場合はそうではないので、コンパイラは long long で、うまく収まる。