C では、次のような関数またはマクロを作成したいと考えています。
void Log(char* what, ...)
... は const char* のキーと値のペアでなければなりません。これに従わないコードがコンパイル時に爆発することを本当に望んでいます。これを行う __attribute((..)) ディレクティブを探してみましたが、役に立ちませんでした。何か案は?
C では、次のような関数またはマクロを作成したいと考えています。
void Log(char* what, ...)
... は const char* のキーと値のペアでなければなりません。これに従わないコードがコンパイル時に爆発することを本当に望んでいます。これを行う __attribute((..)) ディレクティブを探してみましたが、役に立ちませんでした。何か案は?
C には、任意の可変個引数に対してタイプ セーフを適用する方法がありません。GCC と Clang には__attribute__
、いくつかの固定ケース用の s があります (可変引数関数で最後の引数が であると予想されるNULL
場合は を使用できます__sentinel__
; または書式文字列の場合は を使用できますformat
)、一般的な解決策はありません。
一方、C++11 にはこの問題を解決するための可変個引数テンプレートがありますが、C で作業しているとのことなので、うまくいきません。
さて、私は回避策を見つけました:
#define ASSERT_LIST_TYPE(t, l...) do{t _t[] = {l};}while(0)
void _Log(char* what, ...);
#define Log(what, args...) do{\
ASSERT_LIST_TYPE(char*, args);\
_Log(what, args);\
}while(0)
ダミー配列の初期化が正しいタイプではないため、引数が正しいタイプでない場合、少なくとも警告が生成されます。
念のため、これがデバッグ ビルドでない場合は、ASSERT_LIST_TYPE を #ifdef する予定です。
** 編集 **
ここでのフィードバックに基づいて、コードを次のように変更しました。
void _Log(char* what, const char** args, size_t args_len);
#define Log(what, args...) do{\
const char* a[] = {args};\
_Log(what, a, (sizeof a)/sizeof(char*));
}while(0)
これは args が空の場合でも機能するように見え、代わりに obj-c リテラル文字列 ("..." ではなく @"...") を渡す人をキャッチします。