読者です 読者をやめる 読者になる 読者になる

printf 用のマクロの話

C言語 Advent Calendar 2015 - Qiita 向け


15年ほどC++書いてるんですが、どんどん自分の書くコードがbetter Cになっていっているような気がしています。どんどん先進性みたいなのが劣化している気がするので、特に高度なことは書かない…というか書けないです。

で、なんか C++ でも printf を使ってしまう傾向にあります。

  • cerr だと endl 書かないといけないのがめんどくさいけど自動で改行足すようなやつ作るのは少しめんどくさい
  • フォーマット指定子が思い出せない

という2点が主な理由かなあと思います。あとなんか % で書いてある方が出力が予想しやすいことが多いような気がするんですよね。特に括弧とかがたくさん登場する場合。

LOG("setenv(%s, %s)", name, value);
LOG << "setenv(" << name << ", " << value << ")";

のどっちが良いかというような話。

iostream 使えば operator<< のオーバーロードで自分の型でも表示できる、てのが嬉しいということがあるかと思うんですが、このへんはマクロ使うと少しラクになったりとか。例えば kati ではファイル名と行番号を保持する

typedef struct {
  const char* filename;
  int lineno;
} Loc;

みたいな型があったんですが、これを出力するために

#define LOCF(loc) loc.filename, loc.lineno

みたいなマクロを定義して

Loc loc;
fprintf(stderr, "%s:%d: something something\n", LOCF(loc));

みたいな感じで使っていました。このマクロだと LOCF に渡したものに副作用があると二度評価されてしまいますが、まあ普通問題にはならないでしょう。。

次の例はヌル終端してない、 Pascal 文字列のようなやつ。

class StringPiece {
 public:
  const char* data() const { return ptr_; }
  size_type size() const { return length_; }
};

これも

#define SPF(s) static_cast<int>((s).size()), (s).data()

みたいなマクロを定義してやると、

StringPiece str;
fprintf(stderr, "str=%.*s\n", SPF(str));

というようにすると出力できたりします。 %.*s で文字数を変数で指定できる、ていうちょっとマイナー気味な機能を使っています。

他のマクロネタも書こうかと思ってたんですけど、なんか nothingcosmos さんのやつとかぶってるような、かぶってないようなという感じだったので、書き気も起きなくなったので省略。

なにかあれば下記メールアドレスへ。
shinichiro.hamaji _at_ gmail.com
shinichiro.h