マイコンのデバッグの際USART経由でコンソールにprintfと等しい出力をさせるためこんな書き方をしていました。

sprintf(buffer, "\r\nTime:%s", __TIME__); // sprintfで文字列バッファbufferに書式付きで出力
USARTPutString(buffer); // 文字列バッファbufferをUSARTで出力

これでもいいのですが、毎度デバッグ出力のたびに2行必要なのであまりスマートな記述方法ではないなと思いながらずっとこんな書き方をしてました(^^;A

ところが最近になって"可変長引数"という存在を知り、長年のモヤモヤが一気に解消に!

printfはconst char *と...という引数で定義されています。
const char *にあたる部分が書式や文字列にあたり、...が可変長引数に相当します。
この...(可変長引数)が今回の話のミソでして、コイツをうまく扱えばprintfのラッパーのような関数が作れるのでは?と考えました。

ぐぐってみるとたくさんヒットしました。
その中でvsprintfを使うという超お手軽な方法があることを知り、最終的に下のようなprintのラッパーが完成しました。

#include <stdio.h>
#include <stdarg.h>

int USARTPrintf(const char *fmt, ...){
static char buffer[100];
int ret;
va_list ap;

va_start(ap, fmt);
ret = vsprintf(buffer, fmt, ap);
USARTPutString(buffer);
va_end(ap);

return ret;
}


va_listは可変長引数を扱うための構造体をつくり、va_start、va_end等は可変長引数を扱うために必要なマクロです。(詳しいことはわかりません汗)
vsprintfは可変長引数を扱うための構造体をそのまま取り込み、printfのような処理をしてバッファに書式付きで出力してくれます。

これでUSARTPrintf("\r\nTime:%s", __TIME__);などとすると一行記述でprintfと同等の結果が得られました。

しかしprintfという名前がどうしても使いたくてもうちょっとかっこよくするためにdebugという構造体をつくり、その中でprintfという関数の型を定義し上で作ったUSARTPrintfをアサインさせて予約語の重複を回避させました。

volatile struct {
int (*printf)(const char *, ...);
} debug;


debug.printf = USARTPrintf;

debug.printf("\r\nTime:%s", __TIME__); // なんかかっこいいかも!

ということで自己満足だけどやっとスッキリしたUSART版printfが完成したのでありましたー(^ω^)