ルギア君「, −−! (ファギクンジェルバ、ハローワールド!)」
メタグロス「何だい? その魔法は?」
ルギア君「あれ、じゃあ、何でキノガッサはできたの?」
メタグロス「キノガッサは、あのときはすでに魔法を教えてくれたからだ。」
ルギア君「というと・・・?」
メタグロス「俺はごく一部最低限の魔法しか覚えていない。だから、俺が覚えていない魔法はいちいち教えてくれないと使えないんだ。」
ルギア君「使うにはどうすればいい?」
メタグロス「それはリザードに教えてもらってくれ。」
ルギア君「・・・というわけなんだけど・・・」
リザード「それなら、この魔法を唱えればいい。」
ルギア君「えーっと、− − −− . (ズポーファ クンサガーネ ルクジーニーオクエー ネムジェ ルムジク)」
すると、リザードの机にあった本のひとつが飛び出して、メタグロスの部屋のほうへ飛んでいった。
ルギア君「これでいいの?」
メタグロス「おう。 の魔法の情報がちゃんと入っている。」
ルギア君「, −−! (ファギクンジェルバ、ハローワールド!)」
リザード「おっと、開始する魔法を忘れているぜ。」
ルギア君「ああ、そっか・・・ , ・・・ (クンジェ チークン スムセ ・・・)」
つづく
まとめ
こないだのプログラムはコンパイラによってはエラーにあることもあります。
printf は未定義の関数です。*1
のような感じで。これが物語に完全に一致します。
これをコンパイルできるようにするには、
int main(void)
よりも前(上)に
#include <stdio.h>
と書いてやります。 stdio.h が、メタグロスの元に送られた「本」になります。
この本の中に printf に関する情報がはいているため、メタグロスは正しく実行できるわけです。
ということで今回できたプログラムは
となります。
Visual C++ でビルドすると前回出てきた warning は無事なくなります。
gcc では、何も変わりません。
では、前回の謎を解決しましょう。
ちょっと話が難しくなりますので注意してください。
C言語では BASIC *2 や なでしこ のように「上から順に実行」ではなく、「『int main(void) {』という場所から実行」するように文法ができています。しかしながらメタグロスはプログラムを「上から順に実行」しようとするので、プログラム本体よりも前に『int main(void)』までジャンプさせる(飛ばす)ことが必要です。これをやるプログラムを「スタートアッププログラム」と呼ばれ、crt とかかれます。
gcc では
#include <stdio.h>
の記述をしなくても、stdio.h の内容は勝手に挿入されますのでエラーも warning (警告)も出てきません。
Visual C++ では
stdio.h の内容は勝手に挿入されはするんですが、それは、スタートアッププログラムに組み込まれています。
stdio.h がスタートアッププログラムの中にすでに組み込まれているため、コンパイラがその内容を知ることができません。
そのため、『printf は 定義されていません。int を返す外部関数(スタートアッププログラムも外部)とみなします。』という警告が出てきます。
エラーではなく警告なのは、スタートアップに入っているかもしれないということで、実行できるようにしているのです。
もし、ここに入っていないと実行するときにとんでもないことになってしまいます。
さて、
#include <stdio.h>
と書きましたが、なにか気づくことはないでしょうか。
それは、C言語では分の終わりに書くはずだった「; (セミコロン)」がないことだろうと思います。
では、文の終わりは何なのかというと、ここでは改行になっているのです。
そうすると、文の終わりが2つもあるとことになり、コンパイラは混乱してしまうはずです。
では、なぜコンパイラは混乱しないのでしょうか。
それは、先頭に秘密があります。
この魔法の先頭には # がついていますね。
この # が重要なのです。
つまり、# があるときには改行が文の終わり、ないときは ; が文の終わりとみなすのです。(例外もあるが混乱するものではない。)