質問: scanf("%d", &n); if(ret_scanf != 1)//不正な文字があって入力に失敗した while(getchar()!='\n');//残っている入力を消費する } while(n < 0 || ret_scanf != 1);//負の値か不正入力があった場合繰り返す ``` コードの目的は`int`の値を入力させて不正な入力や負の値が入力されたら再入力させるというものです。 (単なる例です、EOFの場合を考慮してないとかは無しで) 不正入力があって、`n`に値が設定されなかった場合 `n < 0 || ret_scanf != 1` での `n < 0` の部分は`n`が未初期化なので動作未定義です。 動作未定義の場合の1つ > > The value of an object with automatic storage duration is used while it is indeterminate > > > でも入力が不正だった場合`ret_scanf` が`0`になり、 `ret_scanf != 1`の部分が真になるので、 `n < 0` の部分で`n`の値がどのような値になっていて、 つまりこの部分の式の結果が真であろうと偽であろうと全体としては真になるものと思います。 つまり質問としては、 (通常動作未定義の部分を含むような式は全体においても動作未定義だと思われるが) 例のような場合、 全体としての式はやはり動作未定義ですか? それとも動作未定義ではないのでしょうか? (`ret_scanf != 1 || n < 0` とするべきとかは無しでね、例としてあげてるだけなので)
回答: 要点をはっきりさせるためのまとめ c11ドラフトから引用 > > 3.4.3 > > > 1. **undefined behavior** > > behavior, upon use of a nonportable or erroneous program construct or of erroneous data, for which this International Standard imposes no requirements > 2. NOTE Possible undefined behavior ranges from ignoring the situation completely with unpredictable results, to behaving during translation or program execution in a documented manner characteristic of the environment (with or without the issuance of a diagnostic message), to terminating a translation or execution (with the issuance of a diagnostic message). > > > 「移植性のないまたは誤ったプログラム構成の使用時または誤ったデータの使用時に、 この国際規格は要求を課さない」 つまり、「未定義動作のプログラムの使用による結果は規定されない。」ということであって、 プログラマが期待するような実行をしてもいいし、 該当部分を削除してしまってもいい(プログラマが期待しないような実行をしてもよい)し、 「未初期化な変数を使用している」とメッセージを表示してコンパイルを止めてもよい。 等々。 > > 「例のような場合、 全体としての式はやはり動作未定義ですか? それとも動作未定義ではないのでしょうか?」 > > > に対しての回答は、「動作未定義である」ということになります。 プログラムの実際の動作として、 それが部分的なものにできるかできないか(言い換えればプログラマの期待通りに動作するかしないか)というのも 結局のところ、コンパイラやその環境による(あるコンパイラでは期待するようなコードを出力し期待するように動作するかもしれないが、別のコンパイラではそうではないかもしれない)ので、 **それが、プログラマの期待するように動作すると期待してはいけない**。