3

C++ 標準 (5/5) によると、ゼロ除算は未定義の動作です。次に、このコードを考えてみましょう (コンパイラがコードを最適化するのを防ぐために、多くの役に立たないステートメントがあります)。

int main()
{
    char buffer[1] = {};
    int len = strlen( buffer );
    if( len / 0 ) {
        rand();
    }
}

Visual C++ は、次のifようにステートメントをコンパイルします。

sub         eax,edx 
cdq 
xor         ecx,ecx 
idiv        eax,ecx 
test        eax,eax 
je          wmain+2Ah (40102Ah) 
call        rand

明らかに、コンパイラはコードがゼロで除算されることを認識しています。xor x,xパターンを使用してゼロを設定しecx、整数除算の 2 番目のオペランドを提供します。このコードは、実行時に「ゼロによる整数除算」エラーを確実に引き起こします。

IMO のようなケース (コードが常にゼロで除算されることをコンパイラが認識している場合) は、コンパイル時エラーの価値があります。標準ではそれを禁止していません。これは、実行時ではなくコンパイル時にそのようなケースを診断するのに役立ちます。

しかし、私は他の何人かの開発者と話をしましたが、彼らは反対しているようです - 彼らの反対は、「作者がゼロで割って... emm... エラー処理をテストしたい場合はどうですか?」というものです。

__declspec(noinline)Visual C++ 固有の関数デコレータを使用して、コンパイラを認識せずに意図的にゼロで除算することはそれほど難しくありません。

__declspec(noinline)
void divide( int what, int byWhat )
{
    if( what/byWhat ) {
       rand();
    }
}

void divideByZero()
{
    divide( 0, 0 );
}

これははるかに読みやすく、保守しやすいものです。「エラー処理をテストする必要がある」ときにその関数を使用でき、他のすべての場合に適切なコンパイル時エラーが発生します。

何か不足していますか?コンパイラがゼロ除算を認識しているコードの発行を許可する必要がありますか?

4

5 に答える 5

4

呼び出されることのない関数で誤ってゼロ除算を行うコードが存在する可能性があり (たとえば、プラットフォーム固有のマクロ展開が原因で)、これらはコンパイラでコンパイルされなくなり、コンパイラの有用性が低下します。

また、実際のコードで見たゼロによる除算のエラーのほとんどは、入力に依存しているか、少なくとも静的解析には適していません。たぶん、チェックを実行する努力に値するものではありません。

于 2011-10-17T07:05:31.977 に答える
4

0 で除算すると、特定のプラットフォームでハードウェア例外が発生する可能性があるため、未定義の動作です。私たちは皆、より良い動作のハードウェアを望むことができますが、-INF/+INF および NaN 値を持つ整数を持つことが適切だと誰も考えたことがないため、まったく無意味です。

さて、これは未定義の動作であるため、興味深いことが起こる可能性があります。未定義の動作と最適化に関する Chris Lattner の記事を読むことをお勧めします。ここでは簡単な例を示します。

int foo(char* buf, int i) {
  if (5 / i == 3) {
    return 1;
  }

  if (buf != buf + i) {
    return 2;
  }

  return 0;
}

は除数として使用されるためi、0 ではありません。したがって、2 番目ifは自明であり、最適化して取り除くことができます。

このような変換に直面して、0 による除算の正気な動作を望んでいる人は誰でも、ひどくがっかりするでしょう。

于 2011-10-17T07:13:38.477 に答える
1

整数型 (int, short, longなど) の場合、意図的なゼロ除算の用途は考えられません。

ただし、IEEE 準拠のハードウェア上の浮動小数点型の場合、明示的なゼロ除算は非常に便利です。これを使用して、数値 (NaN、0/0) 値ではなく、正および負の無限大 (+/- 1/0) を生成できます。これは非常に役立ちます。

並べ替えアルゴリズムの場合、無限大を初期値として使用して、可能なすべての値よりも大きいか小さいかを表すことができます。

データ分析の目的で、NaN を使用して欠落したデータまたは無効なデータを示し、適切に処理できます。たとえば、Matlab は明示的な NaN 値を使用して、プロットなどで欠落しているデータを抑制します。

これらの値にはマクロと std::numeric_limits (C++) を使用してアクセスできますが、独自に作成できると便利です (そして、多くの「特殊なケース」コードを回避できます)。また、標準ライブラリの実装者は、これらの値を提供するためにハッカー (正しい FP ビット シーケンスを手動で組み立てるなど) に頼ることを回避できます。

于 2011-10-17T07:35:41.993 に答える
0

コンパイラが 0 による除算を検出した場合、コンパイラ エラーはまったく問題ありません。あなたが話した開発者は間違っています。そのロジックをすべてのコンパイル エラーに適用できます。0 で割っても意味がありません。

于 2011-10-17T06:58:51.820 に答える
0

コンパイル時にゼロによる除算を検出することは、コンパイラの警告にしたいようなものです。それは間違いなくいいアイデアです。

私は Microsoft Visual C++ とは何の関係もありませんが、G++ 4.2.1そのようなチェックを行っています。コンパイルしてみてください:

#include <iostream>

int main() {
    int x = 1;
    int y = x / 0;
    std::cout << y;
    return 0;
}

そしてそれはあなたに言うでしょう:

test.cpp: In function ‘int main()’:
test.cpp:5: warning: division by zero in ‘x / 0’

しかし、それをエラーと考えると、経験豊富な人が余暇をあまり登らないように知っている滑りやすい斜面です。私が書いたときに G++ が何も言うことがない理由を考えてみましょう:

int main() {
    while (true) {
    }
    return 0;
}

それをコンパイルするべきだと思いますか、それともエラーを出しますか? 常に警告する必要がありますか?そのようなすべての場合に介入する必要があると思われる場合は、正常終了を保証するプログラムのみをコンパイルする、あなたが作成したコンパイラーのコピーをお待ちしています! :-)

于 2011-10-17T07:46:23.573 に答える