いいえ、これは整数オーバーフローを検出する方法の複製ではありませんか? . 問題は同じですが、質問は異なります。
gcc コンパイラは、(-O2 を使用して) オーバーフロー チェックを最適化して取り除くことができます。次に例を示します。
int a, b;
b = abs(a); // will overflow if a = 0x80000000
if (b < 0) printf("overflow"); // optimized away
gcc の人々は、これはバグではないと主張しています。C 標準によれば、オーバーフローは未定義の動作であり、コンパイラは何でも実行できます。どうやら、オーバーフローが発生しないことを前提としたものは何でも含まれているようです。残念ながら、これにより、コンパイラはオーバーフロー チェックを最適化できなくなります。
オーバーフローをチェックする安全な方法は、最近のCERT 論文に記載されています。この論文では、2 つの整数を加算する前に次のようなことを行うことを推奨しています。
if ( ((si1^si2) | (((si1^(~(si1^si2) & INT_MIN)) + si2)^si2)) >= 0) {
/* handle error condition */
} else {
sum = si1 + si2;
}
どうやら、結果が有効であることを確認したい場合、一連の計算で +、-、*、/ およびその他の操作の前に、このようなことを行う必要があるようです。たとえば、配列インデックスが範囲外でないことを確認したい場合。これは非常に面倒なので、実際に誰も行っていません。少なくとも、これを体系的に行う C/C++ プログラムは見たことがありません。
さて、これは根本的な問題です:
配列にアクセスする前に配列インデックスをチェックすることは便利ですが、信頼性は高くありません。
CERT 法による一連の計算のすべての操作をチェックすることは信頼できますが、役に立ちません。
結論: C/C++ でオーバーフローをチェックする便利で信頼できる方法はありません!
標準が書かれたときにこれが意図されていたとは信じられません。
問題を解決できる特定のコマンド ライン オプションがあることは知っていますが、標準またはその現在の解釈に根本的な問題があるという事実は変わりません。
ここで私の質問は次のとおりです。gcc の人々は、オーバーフロー チェックを最適化して取り除くことを許可するときに「未定義の動作」の解釈を取りすぎているのでしょうか、それとも C/C++ 標準が壊れているのでしょうか?
追加された注: 申し訳ありませんが、私の質問を誤解している可能性があります。私は問題を回避する方法を尋ねているのではありません - それはすでに他の場所で回答されています。C 標準について、より基本的な質問をしています。オーバーフローをチェックする便利で信頼できる方法がない場合、言語自体が怪しいです。たとえば、境界チェックを使用して安全な配列クラスを作成した場合、安全であるはずですが、境界チェックを最適化して取り除くことができる場合はそうではありません。
規格がこれを可能にする場合、規格を改訂する必要があるか、規格の解釈を改訂する必要があります。
注 2 を追加: ここにいる人々は、「未定義の動作」という疑わしい概念について議論したがらないようです。C99 標準に 191 種類の未定義の動作がリストされているという事実 (リンク) は、ずさんな標準を示しています。
多くのプログラマーは、「未定義の動作」により、ハードディスクのフォーマットを含め、あらゆることを行うライセンスが得られるという声明をすぐに受け入れます。標準が整数オーバーフローを配列境界外への書き込みと同じ危険なカテゴリに分類しているのは問題だと思います。
これら 2 種類の「未定義の動作」が異なるのはなぜですか? なぜなら:
多くのプログラムは、整数のオーバーフローが無害であることに依存していますが、何があるか分からない場合に、配列境界の外側に書き込むことに依存するプログラムはほとんどありません。
配列の境界外に書き込むと、実際にはハードディスクをフォーマットするのと同じくらい悪いことをする可能性があり (少なくとも DOS のような保護されていない OS では)、ほとんどのプログラマーはこれが危険であることを知っています。
整数オーバーフローを危険な「なんでもあり」カテゴリに入れると、コンパイラが何をしているのかについて嘘をつくことを含め、コンパイラが何でもできるようになります (オーバーフロー チェックが最適化されていない場合)。
配列境界外への書き込みなどのエラーはデバッガーで見つけることができますが、最適化は通常デバッグ時にオフになっているため、オーバーフロー チェックを最適化して取り除くエラーは発見できません。
gcc コンパイラーは、整数オーバーフローの場合に「なんでもあり」ポリシーを明らかに控えています。オーバーフローが不可能であることを確認できない限り、ループなどの最適化を控える場合が多くあります。なんらかの理由で、gcc 関係者は、ここで「なんでもあり」ポリシーに従えばエラーが多すぎることを認識していましたが、オーバーフロー チェックを最適化して除外するという問題に対しては異なる態度をとっています。
たぶん、ここはそのような哲学的な問題を議論するのに適切な場所ではありません. 少なくとも、ここでのほとんどの回答は的外れです。これを議論するためのより良い場所はありますか?