アカウント名:
パスワード:
C/C++で、他の言語ならコンパイルエラーになるとか例外投げて死ぬとか規定されているべき場面で「未定義」になること。
次みたいな、決めればいいのにってのも未定義だしな。。。 a[i] = i++;
どう決めるべきなの? (ありがちな反応)
(そしてどう決めるべきかで揉めるのもありがち)
コンパイルエラーでいいだろ。どうせ書いてはいけないコードなんだし
実行時に決まるから無理。検出可能な単純なパターンもあるけど、中途半端に検出しても事故の元。
int x = 0, y = 0;int *i, *j;
i = &x;if(hoge){ j = &y;}else{ j = i;}
a[*i] = (*j)++;
だと、実行時のhogeの値によって、未定義動作になるかならないかが変わる。
ちなみに、このプログラムは、「書いてもいい」けど、「実行時にhoge==0となってはいけない」と言うグレーゾーンに位置する。
これ以外の部分の動作により、この部分にさしかかるタイミングではhogeが絶対に0ではないプログラムならOK。この部分にさしかかったときにhogeが0になっている可能性のあるプログラムならNG。
> 実行時に決まるから無理。
静的に検出できるものは検出すればいい。実際clangにはそのようなオプションもある。clang以外でも、たとえば手元のVisual C++ 2013は
int i = 1 / 0;
というコードをコンパイルエラーにしたけど、これは事故の元だからやるなと?
> 検出可能な単純なパターンもあるけど、中途半端に検出しても事故の元。
どんな事故の元になるの? どんな事故が起きるとしても、それは現行の規格でも事故になるものしかありえないはずだけど。
実行時については、未定義を許容することで可能になる最適化があるから仕方ない(今さらどうしようもない)けど。
> i = &x;> if(hoge){> j = &y;> }else{> j = i;> }>> a[*i] = (*j)++;
この例だと、未定義動作のおかげで、いまどきのコンパイラは
i = &x; j = &y;
の場合と同等の、あたかもif文などなかったかのようにコードを生成することが許されている。でも静的に未定義であることが決定できる場合にはそういうメリットはない。
静的に検出できるものは検出すればいい。
仕様で未定義だと言っているのは、つまりコンパイラーで静的に検出できるものはコンパイルエラーにしてもいいよと言っているわけで、あなたが望む通りの仕様になっているんだけど。
よく考えるとこの例の場合もコンパイルエラーにしていいな。hogeが0になることがありえないとわかっているのだからこのコードはコンパイラの最適化に頼らず
i = &x; assert(hoge); j = &y; a[*i] = (*j)++;
と書かれるべきで、未定義になるコードを許すメリットがやっぱりない。
>どんな事故の元になるの? どんな事故が起きるとしても、それは現行の規格でも事故になるものしかありえないはずだけど。
それは確かにその通り。もうちょっとメタな意味。
普通のCプログラマがまず書かないような特殊な書き方の内、さらにそのごく一部を検出するような中途半端な対策に、やる価値のある安全性向上効果があるという発想が危ない。
安全柵に引っかかって助かるというのは相当ヤバい状態なので、そんなのが続けばいつかは柵の隙間から転落して死ぬ。しょっちゅう引っかかるというなら、それは、根本的な行動改善が必要だということを意味する。
その意味では、安全性向上を目的とするのではなく、啓蒙目的で仕込むというのはありかもしれない。検出すると、「未定義動作について調べてから出直してこい、このクソプログラマ」のようなメッセージを表示するとか。
より多くのコメントがこの議論にあるかもしれませんが、JavaScriptが有効ではない環境を使用している場合、クラシックなコメントシステム(D1)に設定を変更する必要があります。
Stableって古いって意味だっけ? -- Debian初級
未定義動作 (スコア:0)
C/C++で、他の言語ならコンパイルエラーになるとか例外投げて死ぬとか規定されているべき場面で「未定義」になること。
Re: (スコア:0)
次みたいな、決めればいいのにってのも未定義だしな。。。
a[i] = i++;
Re: (スコア:2)
どう決めるべきなの? (ありがちな反応)
(そしてどう決めるべきかで揉めるのもありがち)
Re: (スコア:0)
コンパイルエラーでいいだろ。どうせ書いてはいけないコードなんだし
Re: (スコア:1)
実行時に決まるから無理。検出可能な単純なパターンもあるけど、中途半端に検出しても事故の元。
int x = 0, y = 0;
int *i, *j;
i = &x;
if(hoge){
j = &y;
}else{
j = i;
}
a[*i] = (*j)++;
だと、実行時のhogeの値によって、未定義動作になるかならないかが変わる。
ちなみに、このプログラムは、「書いてもいい」けど、「実行時にhoge==0となってはいけない」と言うグレーゾーンに位置する。
これ以外の部分の動作により、この部分にさしかかるタイミングではhogeが絶対に0ではないプログラムならOK。
この部分にさしかかったときにhogeが0になっている可能性のあるプログラムならNG。
Re:未定義動作 (スコア:0)
> 実行時に決まるから無理。
静的に検出できるものは検出すればいい。実際clangにはそのようなオプションもある。clang以外でも、たとえば手元のVisual C++ 2013は
int i = 1 / 0;
というコードをコンパイルエラーにしたけど、これは事故の元だからやるなと?
> 検出可能な単純なパターンもあるけど、中途半端に検出しても事故の元。
どんな事故の元になるの? どんな事故が起きるとしても、それは現行の規格でも事故になるものしかありえないはずだけど。
実行時については、未定義を許容することで可能になる最適化があるから仕方ない(今さらどうしようもない)けど。
> i = &x;
> if(hoge){
> j = &y;
> }else{
> j = i;
> }
>
> a[*i] = (*j)++;
この例だと、未定義動作のおかげで、いまどきのコンパイラは
i = &x;
j = &y;
a[*i] = (*j)++;
の場合と同等の、あたかもif文などなかったかのようにコードを生成することが許されている。でも静的に未定義であることが決定できる場合にはそういうメリットはない。
Re:未定義動作 (スコア:2)
仕様で未定義だと言っているのは、つまりコンパイラーで静的に検出できるものはコンパイルエラーにしてもいいよと言っているわけで、あなたが望む通りの仕様になっているんだけど。
Re: (スコア:0)
> i = &x;
> if(hoge){
> j = &y;
> }else{
> j = i;
> }
>
> a[*i] = (*j)++;
よく考えるとこの例の場合もコンパイルエラーにしていいな。hogeが0になることがありえないとわかっているのだからこのコードはコンパイラの最適化に頼らず
i = &x;
assert(hoge);
j = &y;
a[*i] = (*j)++;
と書かれるべきで、未定義になるコードを許すメリットがやっぱりない。
Re: (スコア:0)
>どんな事故の元になるの? どんな事故が起きるとしても、それは現行の規格でも事故になるものしかありえないはずだけど。
それは確かにその通り。もうちょっとメタな意味。
普通のCプログラマがまず書かないような特殊な書き方の内、さらにそのごく一部を検出するような中途半端な対策に、
やる価値のある安全性向上効果があるという発想が危ない。
安全柵に引っかかって助かるというのは相当ヤバい状態なので、そんなのが続けばいつかは柵の隙間から転落して死ぬ。
しょっちゅう引っかかるというなら、それは、根本的な行動改善が必要だということを意味する。
その意味では、安全性向上を目的とするのではなく、啓蒙目的で仕込むというのはありかもしれない。
検出すると、「未定義動作について調べてから出直してこい、このクソプログラマ」のようなメッセージを表示するとか。