web-dev-qa-db-ja.com

0による未評価の除算は未定義の動作ですか?

私は、次のコードについて同僚と意見が分かれています。

int foo ( int a, int b )
{
    return b > 0 ? a / b : a;
}

このコードは未定義の動作を示しますか?

編集:b > 0チェックが最適化された、過度に熱心な最適化コンパイラのバグと思われるものから意見の相違が始まりました。

61
Luchian Grigore

番号。


N4140からの引用:

§5.16[expr.cond]/1

条件式は右から左にグループ化します。最初の式は文脈的にブールに変換されます。評価され、真の場合、条件式の結果は2番目の式の値になり、そうでない場合は3番目の式の値になります。 1つのみ2番目と3番目の式が評価されます

さらに:

§5[expr]/4

式の評価中に、結果が数学的に定義されていないか、そのタイプの表現可能な値の範囲にない場合、動作は未定義です。

これは明らかにここでは起こりません。同じ段落では、ノートで明示的にゼロによる除算に言及しており、規範的ではありませんが、この状況に関連することがさらに明確になっています。

[注:C++の既存の実装のほとんどは、整数オーバーフローを無視します。ゼロ除算の処理、ゼロ除数を使用した剰余の形成、およびすべての浮動小数点例外はマシンによって異なり、通常はライブラリ関数によって調整可能です。 —注を終了]


上記の点を補強する状況証拠もあります。条件演算子は、条件付きで動作を未定義にするために使用されます。

§8.5[dcl.init] /12.3

int f(bool b) {
  unsigned char c;
  unsigned char d = c; // OK, d has an indeterminate value
  int e = d; // undefined behavior
  return b ? d : 0; // undefined behavior if b is true
}

上記の例では、dを使用してint(またはunsigned char)は未定義です。しかし、UBブランチが評価された場合にのみ、UBが発生することが明確に述べられています。


言語弁護士の観点から外れると、これがUBである可能性がある場合、除数は潜在的に0である可能性があるため、すべての部門はUBとして扱われます。これはルールの精神ではありません。

109
krzaq

サンプルコードでは、ゼロで除算する方法はありません。プロセッサがa / bを実行するとき、b > 0であることがすでに確認されているため、bがゼロ以外です。

a == INT_MINおよびb == -1の場合、a/bも未定義の動作であることに注意してください。ただし、この場合は条件がfalseと評価されるため、これはとにかく防止されます。

return b != 0 ? a / b : a;ではなくreturn b > 0 ? a / b : a;を意味したかどうかはよくわかりませんが、bがゼロ未満の場合、上記の条件でない限り、除算はまだ有効です。

15
glauxosdever

このコードは未定義の動作を示しますか?

いいえ。そうではありません。表現

return b > 0 ? a / b : a;  

と同等です

if(b > 0)
    return a/b;     // this will be executed only when b is greater than 0
else
    return a;  

除算は、b0より大きい場合にのみ実行されます。

9
haccks

これがUBだったら

if(a != null && *a == 42)
{
 .....
}

そして、ifs、ands、orsのシーケンスは、明確にこのタイプの構成を許可するように設計されています。あなたの同僚がそれについて議論すると想像することはできません

3
pm100