ページ 11

【雑談】「コンパイラはプログラマの心を察してくれる」と感じた経験はありますか?

Posted: 2010年7月03日(土) 00:35
by たかぎ
うちのサイトに、
http://www.kijineko.co.jp/tech/supersti ... eader.html
といった記事があります。
これに関して具体例を挙げて説明しようとすると、なかなかこれといった例が思いつきません。
そこで、皆さんのいろいろな体験を聞かせていただけないでしょうか?
レベルの高い、低いは問いません。

Re:【雑談】「コンパイラはプログラマの心を察してくれる」と感じた経験はありますか?

Posted: 2010年7月03日(土) 03:31
by わふー
こんにちは。
構造体とかクラスなどへのポインタpを作り、p.Init();としたときなどに「代わりに '->' を使用しますか?」と聞いてくれることですとか?
こんな感じの解答でいいんでしょうかね?

Re:【雑談】「コンパイラはプログラマの心を察してくれる」と感じた経験はありますか?

Posted: 2010年7月03日(土) 03:56
by たかぎ
> 構造体とかクラスなどへのポインタpを作り、p.Init();としたときなどに「代わりに '->' を使用しますか?」と聞いてくれることですとか?

ちょっと違います。
わかりやすい例でいうと...

if (1 <= month <= 12) /* 月の値は1から12でなければならない */
{
...
}
else
{
/* エラー処理 */
}

とか、


#include <stdio.h>

struct A
{
int value;
}

static a;

int main(void)
{
printf("%d\n", a);
return 0;
}

のようなものですかね。

Re:【雑談】「コンパイラはプログラマの心を察してくれる」と感じた経験はありますか?

Posted: 2010年7月03日(土) 12:29
by ookami
代入と比較を間違えて
if(i=1){...}
とかですかね。私はBasicから入ったので最初戸惑いました。

Re:【雑談】「コンパイラはプログラマの心を察してくれる」と感じた経験はありますか?

Posted: 2010年7月03日(土) 13:37
by fatens
#include <stdio.h>

int main(void)
{
int a = 2;
int b = 3;
double c = (a + b) / 2; /* aとbの平均のつもり */

printf("c = %f\n", c);

return 0;
}

こういうのをやってしまったことがあったと思います。


以下「プログラマーのためのソースコードを読む技術」に関することです。
もうご存知のことかもしれませんが、お時間があるときにでも確認していただければ。
P.23 本文
    && 演算子は短絡評価を行います.
 → || 演算子の間違いだと思います。
P.58 [ブロックを単位としたスコープがないPHP]
    $a = 1; (C)
 → C言語の方ではint a = 2;なので、こちらも$a = 2ではないでしょうか。
P.60 [C++のデストラクタ]
    foo x; (xのデストラクタはfunc関数から抜ける時点で呼び出される)
 → func関数ではなくg関数だと思います。
P.71 本文
    ソースコードを可読性を上げることができます。
 → ソースコードの ではないでしょうか。
    そのあとの文ではそうなっています。
P.80 [単純なスタックの実装例]
    *sp = value;
    int value = *sp;
 → stack[sp] = value;
    int value = stack[sp];
    ではないでしょうか。
奥付
    2010年7月10日 初版 第1刷発行
 → これを書いているのが7月3日なので……
まだまだ読み解けていないので、もう何度か読み返したいと思います。

Re:【雑談】「コンパイラはプログラマの心を察してくれる」と感じた経験はありますか?

Posted: 2010年7月03日(土) 13:48
by たかぎ
ookamiさん、fatensさん、情報ありがとうございます。
両方ともありがちですね。

あと、fatensさん
本に関する内容はここでレスするときりがなくなるので、メールでご連絡いただけると助かります。

Re:【雑談】「コンパイラはプログラマの心を察してくれる」と感じた経験はありますか?

Posted: 2010年7月03日(土) 13:53
by fatens
分かりました。
もし今後何かあればそのようにします。

Re:【雑談】「コンパイラはプログラマの心を察してくれる」と感じた経験はありますか?

Posted: 2010年7月03日(土) 14:44
by s-rush
#include <stdio.h>

int main(void){
  int a = 10;
  int b = 20;

  /*aとbの入れ替え*/
  a = b;
  b = a;
  printf("a=%d b=%d\n", a, b);
  return 0;
}
C言語を勉強し始めた人で、変数の中身を入れ替える処理でこのように書いちゃう人が
結構な確率でいるような気がします^^;

って言ってる私も同じミスをした人の1人ですがorz


コンパイラにも人工知能的な技術が組み込まれて、
人間の心を察して補間してくれるような日が来るんでしょうかね?

こういうようなコンパイラがあれば、バグ解析も楽になるのでは・・・
と、素人の甘い考えですいません^^;

けど、大規模なプログラムのバグってしょうもないミスが多いんですよね
1をiと書き間違っていたり、
if(cnt=1)としてしまっていたり・・・

Re:【雑談】「コンパイラはプログラマの心を察してくれる」と感じた経験はありますか?

Posted: 2010年7月03日(土) 15:06
by たかぎ
> C言語を勉強し始めた人で、変数の中身を入れ替える処理でこのように書いちゃう人が
> 結構な確率でいるような気がします^^;

これは今までで一番よい例かもしれませんね。

他には、別の言語ではこうだったので、CやC++でもこうなるに違いないとかいった例もあると教えて下さい。>みなさん

> コンパイラにも人工知能的な技術が組み込まれて、
> 人間の心を察して補間してくれるような日が来るんでしょうかね?

これはかえってコントロールが難しくなります。
書いたとおりに動いてくれる素直なコンパイラが結局は一番使いやすいと思います。

> けど、大規模なプログラムのバグってしょうもないミスが多いんですよね
> 1をiと書き間違っていたり、

こういうのは単純なケアレスミスですね。

Re:【雑談】「コンパイラはプログラマの心を察してくれる」と感じた経験はありますか?

Posted: 2010年7月03日(土) 15:17
by s-rush
>これはかえってコントロールが難しくなります。
>書いたとおりに動いてくれる素直なコンパイラが結局は一番使いやすいと思います。

確かにそうですよね^^;
でも、警告で表示してくれるようになれば便利そうな気はします。
この文章、ほんとに意図して書いたの?
みたいな・・・

>こういうのは単純なケアレスミスですね。
い、痛いところをorz

Re:【雑談】「コンパイラはプログラマの心を察してくれる」と感じた経験はありますか?

Posted: 2010年7月03日(土) 15:33
by たかぎ
こういうコードを見たような気が...

#include <stdio.h>

int main(void)
{
char *x = '123';
int y = x + 1;
printf("%d\n", y);
return 0;
}

123 + 1 なので 124 が出力されるはずなのに、なぜか 3224116 のようなワケの分からない値が出力されます。
とか...

Re:【雑談】「コンパイラはプログラマの心を察してくれる」と感じた経験はありますか?

Posted: 2010年7月03日(土) 17:24
by パコネコ
ワイはポインタの勉強中に中身に+1をしたいのにアドレスに+1とかしちゃうのよく聞きます。
(自分でもある)
まあこれもケアレスミスだと言われればそれまでですが。

Re:【雑談】「コンパイラはプログラマの心を察してくれる」と感じた経験はありますか?

Posted: 2010年7月03日(土) 17:42
by たかぎ
> ワイはポインタの勉強中に中身に+1をしたいのにアドレスに+1とかしちゃうのよく聞きます。
> (自分でもある)
> まあこれもケアレスミスだと言われればそれまでですが。

ちゃんと理解していない場合はダメですね。
理解はしているけれども、単なる打ち間違いとか、編集ミスとかであれば、それはケアレスミスだと思います。

Re:【雑談】「コンパイラはプログラマの心を察してくれる」と感じた経験はありますか?

Posted: 2010年7月03日(土) 17:56
by シエル
察してくれた経験はないですね。

前は予約語を変数名にしてしまったんですが、コンパイラが意味不明な回答をしたので、
原因を突き止めるのに、相当時間がかかりましたw

Re:【雑談】「コンパイラはプログラマの心を察してくれる」と感じた経験はありますか?

Posted: 2010年7月03日(土) 18:11
by たかぎ
> 察してくれた経験はないですね。

そうですか?
実際には動作が未定義になるものであっても、処理系によっては期待通りにコンパイルできて、しかも期待通りに動いてしまうということはよくありますよ。
例えば、int型が32ビットの処理系で、-1 << 32 と書くと、期待通りに 0 になるとかです。

> 前は予約語を変数名にしてしまったんですが、コンパイラが意味不明な回答をしたので、
> 原因を突き止めるのに、相当時間がかかりましたw

これはときどきやりますね。
処理系の独自拡張の予約語が一番危険です。とくに、interface とか...

Re:【雑談】「コンパイラはプログラマの心を察してくれる」と感じた経験はありますか?

Posted: 2010年7月03日(土) 23:57
by ISLe
わたしも察してくれた経験はないです。
既出のは裏切られたサンプルに見えるんですけど。

> 例えば、int型が32ビットの処理系で、-1 << 32 と書くと、期待通りに 0 になるとかです。

-2 >> 1 が絶対に -1 になると思い込んでいる人はもっと多いと思いますね。
未定義ではなくて処理系定義だから分かってて期待する分には良いと思いますけど。


察してくれるというのはこんな↓イメージですか?

LLVMのC/C++コンパイルエラーメッセージはわかりやすい|マイコミジャーナル
http://journal.mycom.co.jp/news/2010/04 ... index.html

Re:【雑談】「コンパイラはプログラマの心を察してくれる」と感じた経験はありますか?

Posted: 2010年7月04日(日) 00:03
by ISLe
失礼しました。

> -1 << 32

は未定義でした(intが32ビットの場合)。

Re:【雑談】「コンパイラはプログラマの心を察してくれる」と感じた経験はありますか?

Posted: 2010年7月04日(日) 00:14
by たかぎ
> 既出のは裏切られたサンプルに見えるんですけど。

ちょっと表現が悪かったので、混乱がありますね。
基本的には、コンパイラは察してくれないものです。
(ただし、処理系によってはたまたま察してくれるケースもないわけではありません)
例えば、


#include <stdio.h>

int main(void)
{
char *x = '123';
int y = x + 1;
printf("%d\n", y);
return 0;
}

のようなコードを書く初心者は、124 が出力されることを期待しているわけです。
しかし、そんな気持ちを察してくれるはずはないので、無残にも裏切られます。
今回の質問は、「察してくれる」と感じたことがあるかどうかですので、このコードを書いた人は、少なくとも動かして絶望するまでは、そのように感じていた可能性があります。

「察してくれる」と感じる原因のひとつが、たまたま察してくれる場合があるということかと思います。
先のシフトもそうですが、

std::vector<std::vector<int>> v;

のようなコードが期待通りにコンパイルできてみたり、

struct A
{
struct B
{
int b;
};
};

struct A a;
a.b = 123;

のようなコードが期待通りに動いてみたりしますので。

> 察してくれるというのはこんな↓イメージですか?
> LLVMのC/C++コンパイルエラーメッセージはわかりやすい|マイコミジャーナル
> http://journal.mycom.co.jp/news/2010/04 ... index.html

このようなエラーや警告メッセージもそうですが、主には実際の動作についてですね。

Re:【雑談】「コンパイラはプログラマの心を察してくれる」と感じた経験はありますか?

Posted: 2010年7月04日(日) 00:20
by たかぎ
> > -1 << 32
> は未定義でした(intが32ビットの場合)。

これは二重の意味で未定義です。
-1 << 1 が -2 になると期待している人は、もっと多いでしょうね(そして、多くの場合、その期待は察してもらえます)。

Re:【雑談】「コンパイラはプログラマの心を察してくれる」と感じた経験はありますか?

Posted: 2010年7月04日(日) 00:47
by ISLe
> 今回の質問は、「察してくれる」と感じたことがあるかどうかですので、このコードを書いた人は、少なくとも動かして絶望するまでは、そのように感じていた可能性があります。

なるほど理解しました。
そうすると裏切られた経験がないと期待していたことにも気付かないのではないでしょうか。

ゲームプログラムでは背景スクロールなど負数に対するビットシフトや剰余を使うことになる機会は多いです。
言語仕様を読むと未定義だったり処理系定義だったりするのですが期待通りに動かないことがありません。
プロのゲームプログラマの中にも一生そのことに気付かない人がたくさんいると思います。

わたしも10年以上知らずにコード書いてました。
いまでもスクロールオフセットを正の数に修正するコードは必要なのか悩みどころです。

Re:【雑談】「コンパイラはプログラマの心を察してくれる」と感じた経験はありますか?

Posted: 2010年7月04日(日) 01:23
by たかぎ
> ゲームプログラムでは背景スクロールなど負数に対するビットシフトや剰余を使うことになる機会は多いです。
> 言語仕様を読むと未定義だったり処理系定義だったりするのですが期待通りに動かないことがありません。
> プロのゲームプログラマの中にも一生そのことに気付かない人がたくさんいると思います。

それはわかります。
規格上は未定義であっても、移植性を捨てるつもりであれば、時には目を瞑ることは必要だと思います(自サイトであまり大声でいうと、リンクを貼られて免罪符にされるのが嫌なのでやりませんが...)。
ただし、動作がドキュメント化されていないのであれば、処理系に何らかの動作保証を求めるのであればやめるべきですし、コンパイル結果の確認なしに安心することもできませんね。

負値の左シフトは、(本当は未定義なのに)コンパイラがプログラマの気持ちを察してくれたかのような振る舞いをする例として挙げました。
しかし、今回求めているのは、気持ちを察してくれて期待通りに動作してくれると思っていたのに、実際にはそうはならなかったという具体例です。

Re:【雑談】「コンパイラはプログラマの心を察してくれる」と感じた経験はありますか?

Posted: 2010年7月04日(日) 01:41
by たかぎ
↓に応えていませんでした。

> そうすると裏切られた経験がないと期待していたことにも気付かないのではないでしょうか。

完全にそうかどうかはともかく、おおむねその通りです。

期待を裏切られることは多々あると思いますが、処理系の不具合や標準準拠度の低さなどが原因のものではなく、プログラマ側に問題がある例を集められればと考えています。

Re:【雑談】「コンパイラはプログラマの心を察してくれる」と感じた経験はありますか?

Posted: 2010年7月04日(日) 01:51
by 組木紙織
まだ、質問を十分理解してないのですが、
C++で継承を使ってるつもりなのにvirtualを関数名の前につけてないとかはどうでしょうか

Re:【雑談】「コンパイラはプログラマの心を察してくれる」と感じた経験はありますか?

Posted: 2010年7月04日(日) 02:03
by たかぎ
> C++で継承を使ってるつもりなのにvirtualを関数名の前につけてないとかはどうでしょうか

すみません。意味がわかりませんでした。
派生クラス側だけでなく、基底クラス側でもvirtualを付けていないのに、オーバーライドしたつもりになっていたということでしょうか?

Re:【雑談】「コンパイラはプログラマの心を察してくれる」と感じた経験はありますか?

Posted: 2010年7月04日(日) 02:09
by 組木紙織
きちんと書かなかったせいで分かりにくくてすみません。

>派生クラス側だけでなく、基底クラス側でもvirtualを付けていないのに、オーバーライドしたつもりになっていたということでしょうか?

そういうことです。

コードで書くなら以下のような感じです。
class Base
{
publc:
virtual f();//ここのvirtualを忘れていた。
};



ほかには、std::auto_ptrの使い方のミスとかもはいるのかな。

Re:【雑談】「コンパイラはプログラマの心を察してくれる」と感じた経験はありますか?

Posted: 2010年7月04日(日) 02:16
by たかぎ
> コードで書くなら以下のような感じです。
> class Base
> {
> publc:
> virtual f();//ここのvirtualを忘れていた。
> };

なるほど。
派生に絡むものだと、次のようなものもありますね。

#include <stdio.h>

struct A
{
virtual void func(int x = 1)
{
printf("A::func(%d)\n", x);
}
};

struct B : A
{
virtual void func(int x = 2)
{
printf("B::func(%d)\n", x);
}
};

int main()
{
B b;
A* p = &b;
p->func(); // B::func(2)が出力されると思っていた。
}

あるいは、

struct A
{
A()
{
func();
}
virtual void func();
};

struct B : A
{
virtual void func();
};

B b; // A::AからB::funcが呼び出されると思っていた。

Re:【雑談】「コンパイラはプログラマの心を察してくれる」と感じた経験はありますか?

Posted: 2010年7月04日(日) 05:03
by めるぽん
#include <iostream>
 
struct Hoge
{
    Hoge() { std::cout << "呼ぶなよ!絶対呼ぶなよ!" << std::endl; }
    Hoge(const Hoge&) { std::cout << "コピーなんて絶対しちゃダメだぞ!" << std::endl; }
};
 
int main()
{
    Hoge h1();
    Hoge h2(Hoge());
}
何も出力されません、とか。
いやこれはむしろ出力されないのが意図通りじゃないんでしょうけど……。

Re:【雑談】「コンパイラはプログラマの心を察してくれる」と感じた経験はありますか?

Posted: 2010年7月04日(日) 05:13
by めるぽん
ふと思ったのですけど、
#include <iostream>
int main()
{
    std::cout << "hoge";
}
とか書いても、ちゃんと std 名前空間に入っている std::operator<<() が呼ばれて、
ちゃんと終了時には文字列がフラッシュされているというのは、
なんかいろいろ察した結果なのかなーと思ったりします。
まあこの場合察したのはコンパイラじゃなくてC++の仕様なんでしょうけど。

Re:【雑談】「コンパイラはプログラマの心を察してくれる」と感じた経験はありますか?

Posted: 2010年7月04日(日) 05:43
by めるぽん
char* p = new char[100];
...
delete p; // delete[/url] じゃないとダメだけど大抵の環境では平気
とかよくありますね。

あと、Pimpl イディオムなんかで、
// hoge.h
#include <memory>
 
struct hoge
{
    hoge();
private:
    struct impl;
    std::auto_ptr<impl> p;
};

// hoge.cpp
#include "hoge.h"
#include <iostream>

struct hoge::impl
{
    impl() { std::cout << "call impl constructor" << std::endl; }
    ~impl() { std::cout << "call impl destructor" << std::endl; }
};

hoge::hoge() : p(new impl) { }
こうしておくと "call impl constructor" は呼ばれるけど "call impl destructor" が呼ばれなかったりします。
でもデストラクタで何もしてない間は気がつかないっていうのとか。
まあこれは大抵コンパイラが不完全型に対する delete に対して警告してくれるから大丈夫でしょうけど。 画像

Re:【雑談】「コンパイラはプログラマの心を察してくれる」と感じた経験はありますか?

Posted: 2010年7月05日(月) 07:00
by たかぎ
めるぽんさん、情報ありがとうございます。

> Hoge h1();
> Hoge h2(Hoge());

このへんは結構やってしまいがちですね(特に後者)。

ここで一旦解決にしたいと思います。