1. ホーム
  2. c++

[解決済み] (A + B + C) ≠ (A + C + B)とコンパイラの並べ替え

2022-11-03 23:54:47

疑問点

2つの32ビット整数を足すと、整数のオーバーフローが発生することがあります。

uint64_t u64_z = u32_x + u32_y;

このオーバーフローは、32ビット整数の1つが最初に64ビット整数にキャストまたは加算された場合に回避することができます。

uint64_t u64_z = u32_x + u64_a + u32_y;

しかし、コンパイラが足し算の順序を変更することにした場合。

uint64_t u64_z = u32_x + u32_y + u64_a;

の場合、整数のオーバーフローが発生する可能性があります。

コンパイラはこのような並べ替えをすることが許されるのでしょうか、それとも結果の矛盾に気づいて式の順序をそのままにしてくれることを信じていいのでしょうか。

どのように解決するのですか?

オプティマイザがそのような並べ替えを行ったとしても、C言語の仕様に縛られているので、そのような並べ替えは、次のようになります。

uint64_t u64_z = (uint64_t)u32_x + (uint64_t)u32_y + u64_a;

根拠を示す。

で始める。

uint64_t u64_z = u32_x + u64_a + u32_y;

足し算は左から右へ行う。

整数昇格ルールでは、元の式における最初の足し算で u32_x に昇格します。 uint64_t . 2回目の追加では u32_y も昇格して uint64_t .

したがって、C言語仕様に準拠するためには、どのオプティマイザも u32_xu32_y を64ビットの符号なし値に変換します。これはキャストを追加することと同じです。(実際の最適化はCレベルでは行われませんが、私たちが理解できる記法なのでC記法を使用しています)。