Fwrapvを使用してコンパイルした場合と使用しない場合で動作が異なるコード例を誰かが提供できますか?.
-fwrapvは、「加算、減算、乗算の符号付き算術オーバーフローを想定し、2の補数表現を使用してラップする」と述べています。
しかし、オーバーフローしようとすると、fwrapvの有無にかかわらず結果は同じになります。
この関数について考えてみてください。
int f(int i) {
return i+1 > i;
}
数学的に言えば、i+1
は、任意の整数i
に対して常にi
より大きくなければなりません。ただし、32ビットのint
の場合、そのステートメントをfalseにするi
の値が1つあります。これは、2147483647
(つまり、0x7FFFFFFF
、つまりINT_MAX
)です。その数に1を追加するとオーバーフローが発生し、2の補数表現によると、新しい値はwrap-aroundになり、-2147483648
になります。したがって、i+1>1
は-2147483648>2147483647
になりますが、これは誤りです。
-fwrapv
なしでコンパイルすると、コンパイラはオーバーフローが「非ラップ」であると見なし、関数を最適化して、常に1
を返します(オーバーフローの場合は無視します)。
with -fwrapv
をコンパイルすると、関数は最適化されませんになり、オーバーフローが「ラッピング」になるため、1を加算して2つの値を比較するロジックがあります。 (つまり、オーバーフローした数値は2の補数表現に従って折り返されます)。
違いは、右側のペインの 生成されたアセンブリ -で簡単に確認できます。-fwrapv
がない場合、関数は常に1
(true
)を返します。
for (int i=0; i>=0; i++)
printf("%d\n", i);
-fwrapv
を使用すると、ループはINT_MAX
の反復後に終了します。 i
の値がi++
の場合、INT_MAX
の評価によって未定義の動作が無条件に呼び出されるため、これがないと何でもできます。実際には、最適化コンパイラはループ条件を省略し、無限ループを生成する可能性があります。
ISO標準ワーキンググループWG14は、すべてのCコンパイラが準拠しなければならない規則を確立するために存在します。一部のコンパイラは、拡張機能も実装する場合があります(実際に実装します)。 ISO標準Cによると、これらの拡張機能は次のいずれかと見なされます。
C11/3.4.3は未定義の振る舞いの定義を確立し、非常に馴染みのある例 を示します。私が書くことができるものよりもはるかに優れています:
1未定義の振る舞い動作、移植不可能または誤ったプログラム構成または誤ったデータの使用時。この国際規格は要件を課していません2注考えられる未定義の動作は、予測できない結果で状況を完全に無視することから、環境に特徴的な文書化された方法で翻訳またはプログラムの実行中に動作すること(診断メッセージの発行の有無にかかわらず)、翻訳または実行の終了(診断メッセージの発行)。
3例未定義の動作の例は、整数オーバーフローの動作です。
不特定の動作もありますが、標準でそれについて読むための演習として残しておきます。
踏む場所に注意してください。これは、一般的に受け入れられている一般的に受け入れられている未定義の動作の1つであり、トラップの表現なしで2の補数表現でLIAスタイルのラッピングが発生すると通常予想されます。すべて1を含むビット表現に対応するトラップ表現を使用する実装があることを理解することが重要です。
要約すると、fwrapv
とftrapv
は、開発者があなたに代わって行わなければならなかった選択をあなたに渡すために存在し、その選択は、符号付き整数オーバーフロー時に起こることです。発生します。もちろん、デフォルトを選択する必要があります。これは、あなたの場合、fwrapv
ではなくftrapv
に相関しているように見えます。そうである必要はなく、これらのコンパイラオプションが何かを変更する場合でもありません。これまで。