35848


例えば、以下のようなコードがあったとします。

[code]

    int n;
    int ret_scanf;
    do {
        ret_scanf = scanf("%d", &n);
        if(ret_scanf != 1)//不正な文字があって入力に失敗した
            while(getchar()!='\n');//残っている入力を消費する
    } while(n < 0 || ret_scanf != 1);//負の値か不正入力があった場合繰り返す
    
[/code]

コードの目的は`int`の値を入力させて不正な入力や負の値が入力されたら再入力させるというものです。  
（単なる例です、ＥＯＦの場合を考慮してないとかは無しで）

不正入力があって、`n`に値が設定されなかった場合  
`n < 0 || ret_scanf != 1` での `n < 0` の部分は`n`が未初期化なので動作未定義です。

動作未定義の場合の１つ

> 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` とするべきとかは無しでね、例としてあげてるだけなので）


CC BY-SA 3.0
2017-06-20T11:40:09.047
35750
2017-06-24T03:20:54.470
5044
question
c
未初期化変数を使用する部分を含む式は全体として動作未定義か？


動作未定義です。

>
> 動作未定義の変数が例えどんな値であっても質問での式の値は真になると思いますが、この場合の式の一部分の動作未定義が全体に波‌​及する理由または根拠はなんですか？

[Undefined, unspecified and implementation-defined
behavior](https://stackoverflow.com/a/4105123/4315484)から引用します。これ自体もC++規格からの引用だそうです。

> Permissible 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).

このように言語仕様はコンパイルエラーも認めています。「もしある実装がコンパイルエラーが発生しなかったとしたらどのような結果になるか？」と仮定した時点で言語仕様から離れて具体的な実装についての議論となります。

BLUEPIXYさんは言語仕様についての議論と具体的実装についての議論の混同が多々見られます（[その１](https://ja.stackoverflow.com/q/31646/4236)、[その２](https://ja.stackoverflow.com/q/34013/4236)）。まずはBLUEPIXYさん自身が言語仕様について知りたいのか具体的実装について知りたいのかをしっかりと自覚してください。

その上で、問題個所を完全に無視することも認められています。つまり`n < 0`がTRUE /
FALSEどちらかを返すことすら保証されておらず、コンパイル時警告無しに`do-while`ループを削除することもあり得ます。

* * *

[Undefined behavior can result in time travel (among other things, but time
travel is the
funkiest)](https://blogs.msdn.microsoft.com/oldnewthing/20140627-00/?p=633/)  
[未定義動作はタイムトラベルを引き起こす（他にもいろいろあるけど、タイムトラベルが一番ぶっ飛んでる）](https://cpplover.blogspot.jp/2014/06/old-
new-thing.html)

が参考になるかもしれません。例えば

> When undefined behavior is invoked, anything is possible. For example, a
> variable can be both true and false.  
>  未定義動作が発動した場合、何でもありだ。例えば、変数は同時にtrueでもfalseでもありえる。

とのことです。


CC BY-SA 3.0
2017-06-20T12:37:53.027
35755
2017-06-20T22:18:21.260
2017-06-20T22:18:21.260
4236
4236
35750
answer


要点をはっきりさせるためのまとめ

[c11ドラフト](http://www.open-std.org/jtc1/sc22/WG14/www/docs/n1570.pdf)から引用

> 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).
>
>

「移植性のないまたは誤ったプログラム構成の使用時または誤ったデータの使用時に、  
この国際規格は要求を課さない」

つまり、「未定義動作のプログラムの使用による結果は規定されない。」ということであって、  
プログラマが期待するような実行をしてもいいし、  
該当部分を削除してしまってもいい（プログラマが期待しないような実行をしてもよい）し、  
「未初期化な変数を使用している」とメッセージを表示してコンパイルを止めてもよい。  
等々。

> 「例のような場合、 全体としての式はやはり動作未定義ですか？ それとも動作未定義ではないのでしょうか？」

に対しての回答は、「動作未定義である」ということになります。

プログラムの実際の動作として、  
それが部分的なものにできるかできないか（言い換えればプログラマの期待通りに動作するかしないか）というのも  
結局のところ、コンパイラやその環境による（あるコンパイラでは期待するようなコードを出力し期待するように動作するかもしれないが、別のコンパイラではそうではないかもしれない）ので、  
**それが、プログラマの期待するように動作すると期待してはいけない** 。


CC BY-SA 3.0
2017-06-24T03:04:34.867
35848
2017-06-24T03:20:54.470
2017-06-24T03:20:54.470
5044
5044
35750
answer