こんにちは、童爺です。
今回からは、Linux(Unix)プログラミングをテーマに記事を書いていこうと思います。
開発環境は、CentOS7です。
ホームディレクトリ配下に、workディレクトリを作ってその中で色々説明して行こうと思います。
最初は、K&RのC言語を中心にやっていきたいと思います。
といっても、ただ解説や補足するだけでは面白くないので、アレンジしたいと思います。
教材は以下のプログラミング言語C 第2版 ANSI規格準拠。
俗に言う、K&R本です。
記念すべき第一回目は、hello, worldです。
Hello, Worldについて
本書では以下の文体になっていると思います。
#include <stdio.h> main() { printf(“hello, world\n”); }
それでは、1行ずつ解説しましょう。
まず、
#include <stdio.h>
ですが、これは標準入出力ライブラリを取り込むと書かれています。
正確には、Standard Input Outputの略で、下線部の文字を取り出しstdio.hとしています。
何故、こんな事をしているかというと、昔のPCはファイル名が8文字以内で拡張子が3文字以内までしか表現できませんでした。
ですので、省略してあります。
今はロングネーム(長い文字名)が使えるので、長い名前を使って解りやすくするのが一般的になっています。
(まあ、それでも短く省略するのが伝統みたいな所もあるので、ケースバイケースですね。)
次に関数のmain()ですが、省略しすぎです。
上記のようなプログラムを組むのであれば、以下の様なのが一般的です。
void main(int argc, char *argv[])
です。
voidは、値を返さないと言う意味。
int argcはプログラム実行時のオプション数。
char *argv[]はプログラム実行時のオプションが文字列で入ってきます。
char **argvと書く人もいます。
これも正解ですが、後々説明するポインタと文字列で、どう違うのか説明したいと思います。
さらに余談ですが、Linux(Unix)で、伝統的なmainの書き方は以下の通りです。
int main(int argc, char *argv[], char *envp[])
です。
既にC言語をマスターしている方は、「おやっ?」と思った人もいるのではないでしょうか?
char *envp[]
が多いですね。
これは、プログラム実行時の環境変数が格納されてきます。
ですが、省略されるのが一般的です。
何故か?
それは、envpを引数でもらわなくても、getenv関数で取得できるからです。
では、何故あるのかと言いますと、getenv関数はglibcというライブラリに含まれているのですが大きすぎて、Linux(Unix)起動時にglibcが読み込まれるまで若干時間がかかります。
なので、glibcが読み込まれるまでの間、例えばカーネルに近い部分のプログラムではenvpで環境変数を取得する必要があります。
脱線しましたね。
では次の
printf(“hello, world\n”);
です。
これは本書に書いてある通りです。
補足として、無条件にstdout(標準出力)に、出力されます。
Linux(Unix)には、三つの標準入出力があります。
stdoutは標準出力。
stderrは標準エラー出力。
stdinは標準入力です。
何故こんなものがあるのでしょう?
それは実践的なプログラムでは、何でもかんでもプログラムから標準出力に出力すると、ただのログなのかエラーで出力したログなのか、見分けが付かないからです。
ですので、fprintf関数を使います。
実際にfprintf関数を使ったプログラムを書いてみましょう。
#inlucde <stdio.h> int main(int argc, char *argv[]) { fprintf(stdout,”hello, world\n”); return 0; }
このプログラムを、以下の様にコンパイルして実行してみましょう。
$ gcc main.c $ ./a.out hello, world $
となります。
では、今度はstderrを使ってみましょう。
#include <stdio.h> int main(int argc, char *argv[]) { fprintf(stdout, “これは正常です!\n”); fprintf(stderr, “これはエラーです!\n”); return 0; }
これを先ほどと同じくコンパイルして実行してみましょう。
ファイル名は解り易く、main_stdio.cとします。
$ gcc main_stdio.c $ ./a.out これは正常です! これはエラーです! $
となります。
これだけでは、メリットは無いように感じますが、以下の様に実行してみて下さい。
$ ./a.out 1> ok.log 2> ng.log $
これで、ok.logとng.logの内容を見てみましょう。
ok.logの中身。
これは正常です!
ng.logの中身
これはエラーです!
となります。
このように、普通の文言とエラー時の文言を分ける事ができます。
まとめ
どうでしょうか?
ただのhello, worldプログラムでも色々奥深いものがあると思います。
たかがhello, worldされど、hello, worldは基本中の基本です。
しっかり理解して次に進みましょう。
それではまた。
でわでわ。