民芸的プログラミング 〜ソフトウェア開発日記〜

アクセスカウンタ

zoom RSS いまさら printf を考察する

<<   作成日時 : 2009/01/08 13:14   >>

ブログ気持玉 0 / トラックバック 0 / コメント 0

C 言語を勉強する際に必ず習う関数として、printf というのがある。
Windows プログラミングでは全くと言っていいほど使わないのだが。

この関数の仕様で気になる点があったので、調べてみた。
printf で気になるのは、引数の数が可変であること。
引数が1つでも、2つでも、20個くらいあっても、きちんと動作する。
C言語では仕様上、引数が可変であっても受け付けられるようになっているので、printf を使う分には何も不思議はないと言われるかもしれない。
それはそのとおりだ。
私が不思議なのは、printf 自体がどのようにプログラミングされているかだ。

va_start だとか、va_lilst だとかを使うのだろうと想像はつくのだが、これらのマクロを使うには、引数の個数はいくらでもいいのだが、とにかく呼び出された関数の側でどうにかして個数を調べられるようになっている必要がある。
引数の個数を第1引数にして渡すとか、最後の引数を必ず NULL にするとかいうように。

しかし、printf の引数にはこのような、引数の数を示す情報は含まれていない。
で、Google で色々と検索してみるとこういうページが見つかった。
http://www.nurs.or.jp/~sug/soft/super/vaarg.htm

なるほど、書式指定子の数で判断しているというわけだ。
このページで紹介されているサンプルが面白そうだったので、手元の cygwin の gcc で同じように入力して試してみた。

#include <stdio.h>
int main(int argc, char *argv[]) {
  int a = 55;
  printf ("%d %d %d\n", 10, 20);
  return 0;
}

これを test.c という名前で保存して、gcc -o test.exe test.c でコンパイルすると...エラーが出ない!
実行結果は

$ ./test.exe
10 20 4198517

3番目の書式指定子のところに当然ながら、変な数字が入っている。
アクセス違反などの例外が出ないということに驚いた。
しかし、これでは上で紹介したページのサンプルのように、a の値が入ってこないので面白くない。
なおちなみに、gcc -o test.ext -Wall test.c でコンパイルすると、

test.c:4: warning: too few arguments for format

という警告が出た。

続いて、結果を面白くするためにプログラムを

#include <stdio.h>
int main(int argc, char *argv[]) {
  printf ("%d %d %d\n", 1, 2, 55);
  printf ("%d %d %d\n", 10, 20);
  return 0;
}

と書き換えてみた。
こうすると、まずスタックに 1 2 55 を積んだ状態で printf が呼ばれ、続いてスタックに 10 20 を積んだ状態で printf が呼ばれることになる。この 2 回目の printf の呼び出しについてだが、C 言語のいい加減さからして、最初のスタックがきれいに掃除されることはないはずなので、最初にスタックに積まれた 55 は残っているはずだ。
という予想の下にこれを実行してみると

$ ./test.exe
1 2 55
10 20 55

思ったとおりの結果を得ることができた。

printf は書式指定子の数で引数を判断しており、仕組みとしては単にスタックをたどっているだけということのようだ。
もっとも、cygwin の gcc 以外でどのような実装になっているかは分からないが。
とにかく、書式指定子の数を間違えると、実行時例外が発生せずに、意図しない範囲までスタックをたどられてしまう恐れがあるので、注意をする必要がありそうだ。

テーマ

関連テーマ 一覧


月別リンク

ブログ気持玉

クリックして気持ちを伝えよう!
ログインしてクリックすれば、自分のブログへのリンクが付きます。
→ログインへ

トラックバック(0件)

タイトル (本文) ブログ名/日時

トラックバック用URL help


自分のブログにトラックバック記事作成(会員用) help

タイトル
本 文

コメント(0件)

内 容 ニックネーム/日時

コメントする help

ニックネーム
本 文
いまさら printf を考察する 民芸的プログラミング 〜ソフトウェア開発日記〜/BIGLOBEウェブリブログ
文字サイズ:       閉じる