crowzの日記: 引数の取り扱いと型変換にハマる5日目 2
前回のソースで、とりあえず決め打ちの日付を出すことには成功したが、課題が2個あった。
1.年月の指定
2.フォーマットが決め打ちなのがダサい。
3.ソースコードが美しくない。
(3は置いておいて)とりあえず1について解決したのでハマった個所を備忘録代わりに。
まず、引数の取り扱いについてだが、それを簡単に行う事のできる関数を発見。
最初はargv[n]で第n+1番目の引数を取っていたのだけども
(n=0のときはプログラムそのものの名前が入るので+1してる)
それでは、引数の順番がバラバラの場合に対応できない。
しかし以下のように書くことによって引数を自動的に解釈してくれた。すごい便利。
// 引数の解析
while(-1!=(option = getopt(argc, argv, "m:y:"))){
switch( option ){
case 'm' : month = atoi(optarg); break;
case 'y' : year = atoi(optarg); break;
}
}
引数を順番に舐めて、-mと-yの直後の値をoptargと言うのに代入してくれるそうだ。
このoptargってどっから来たんだろう?と思って調べてみるとexternと言う型で
"どこかで定義されている変数"であるらしい。一応ファイル先頭で
extern char *optarg;
こう書いておく方がわかりやすくでいいかもしれない。
次にハマったのがこの関数で取得するのはどんな値だろうが文字列として扱われる事。
しかも出力した時に'169321156'見たいな感じで数字が表示されているのでなんのことかわからなかった。
結局、型が違っている事に気付いたがキャストの方法がわからず悩んだもののatoiと言う関数で一発でできた。
とりあえずこれで指定した日付のカレンダーは表示されるようになった。
次はエスケープシーケンスを駆使したカレンダーのフォーマットかな。
externは型じゃないくて記憶クラス。 (スコア:1)
extern:どこかに実体があると信じてる。リンクする時にどこかで実体が定義されてなければリンカが文句を言う。
static:他のモジュール(オブジェクトファイル)からは見えない。初期値が決まってる。初期値を与えなければ0になる。
関数の中で変数を定義すると何も指定しなければ自動変数。
関数の外で変数を定義すると他のモジュールから見える変数(externで引っ張ってくるのはこれ)。これも初期値はstaticと同じ。
型はcharとかintとかlongとかfloatとかdoubleとか、あと構造体とそれらのポインタ(のポインタ...)。
他にconstで「書き換え禁止」にできる。実際には「const hoge」でひとつの型だと識別されてるみたい。
宣言は要らない。 (スコア:1)
> extern char *optarg;
これと同じ宣言はgetopt.hの中に書いてあるので、getopt.hをインクルードしていれば自分で書く必要はありません。
「getopt()とoptargを使うなら、必ずgetopt.hをインクルードして、自分で宣言を書いてはいけない」と憶える方が良いかもしれません。
どうしてもoptargについて何か書かずにはいられないのであれば
みたいに、コメントを書きましょう。
あと、atoi()は使い方こそ簡単ですが、変換に失敗しても黙って無意味な整数を返す性悪な仕様で、
たとえばatoi("123hoge")は123を返します。したがって誤入力には非常に弱いです。ご注意ください。