5

デスクトップでLinuxアプリケーションを実行していて、syslog()呼び出しをprintf()呼び出しにリダイレクトしたいと思いました。

注:通話を置き換えるのではなく、リダイレクトするだけです

だから私はこれを行うためにいくつかのコードを書きました:

#ifndef EMBED
#define syslog(level, stuff) printf("SYSLOG: %s\n", stuff)
#endif

私がそれを使用していた1つのファイルでうまく機能します。これを新しいファイルに移動し、エラーが発生しました:

error: macro "syslog" passed 3 arguments, but takes just 2

エラーは、新しいファイルの呼び出しが混在しているため、syslogに2つの引数を使用しているもの、3つを使用しているものがあることを知っています。また、可変引数リストを介してこれをリダイレクトする必要があることも知っていますが、これをどのように正確に行うのですか?まだ動作していません...

私が理解しているように、syslog()とprintf()は次のようになります。

void syslog(int priority, const char *format, ...)
int printf(const char *format, ...)

だから私は試しました:

#define ERR 3
#ifndef EMBED         // This is not defined in my env, btw
#define syslog(pri, fmt, ...) printf(fmt, ...)
#endif
...
void main() {
...
syslog(ERR, "test");

しかし、それはエラーを与えます:

error: expected expression before ‘...’ token

このマクロの外観/使用方法に関する提案はありますか?

4

3 に答える 3

11

GCCはこの領域に拡張機能を持っていますが、それを処理する最もポータブルな方法は次のとおりです。

#define syslog(priority, ...)    printf(__VA_ARGS__)

優先度は必須ですが、マクロ展開では無視されます。残りの引数(必須の形式とオプションの後続の引数)は、__VA_ARGS__の引数リストで使用されprintf()ます。これは、フォーマット文字列が定数(リテラル)であろうと変数であろうと問題ありません。


のサロゲート用として出力にタグを付けたい場合は、ジョブを実行するsyslog()以外の関数を呼び出します。printf()

#define syslog(priority, ...) syslog_print(__VA_ARGS__)

あるいは

#define syslog(priority, ...) syslog_print(__FILE__, __LINE__, __func__, __VA_ARGS__)

これらは次のように宣言されます。

extern void syslog_printf(const char *fmt, ...);

また:

extern void syslog_printf(const char *file, int line, const char *func,
                          const char *fmt, ...);

実装は、マクロと関数の単純なアプリケーション<stdarg.h>ですv*printf()

void syslog_printf(const char *file, int line, const char *func,
                   const char *fmt, ...)
{
    va_list args;
    printf("SYSLOG:%s:%d:%s: ", file, line, func);
    va_start(args, fmt);
    vprintf(fmt, args);
    va_end(args);
}

タイムスタンプなど、好きなものを追加できます。また、出力を標準出力ではなくファイルに移動するように簡単に調整することもできます。関数内でオンまたはオフにするように調整することもできます。したがって、平均syslog()して、ファシリティのコード使用を調整できるサロゲートに置き換えます。

実際、ロギングの動作を変更する要件を明らかにしたsyslog()ので、コードで直接使用するのではなく、独自の関数(たとえばsyslog_printf()、、場合によっては別の名前で)を使用することをお勧めします。コードを作成し、その関数のさまざまな実装を利用できるようにします。そうすることの唯一の欠点は、本物を呼び出すことsyslog()が今では難しくなっていることですvsyslog()—AFAIKがありません。したがって、への基本的な呼び出しは、を使用しsyslog()て文字列をフォーマットし(または、それが利用可能であり、メモリの枯渇が問題になる可能性が低い場合)、事前にフォーマットされた文字列()を使用して呼び出すことによって行われます。もちろん、リレー先の代理関数に優先順位を渡すこともできます。syslog_printf()vsnprintf()vasprintf()syslog()syslog(priority, "%s", buffer);syslog()

于 2012-08-27T15:06:10.023 に答える
1

文字列には、fmt可変個引数で埋められる独自のフォーマット指定子が含まれている必要があります。まず、実際の引数を無視して、フォーマット文字列を出力するだけです。可変個引数マクロが必要です。

#define syslog(level, fmt, ...) printf("SYSLOG: %s\n", fmt)

次に、巨大なリスクを冒して、ユーザーがフォーマット文字列を変数ではなくリテラルとして提供することを期待している場合は、独自の文字列を連結できます。

#define syslog(level, fmt, ...) printf("SYSLOG[%d] " fmt, level, ##__VA_ARGS__)

これはに対しては機能しますsyslog(1, "Hello");が、に対しては機能しませんsyslog(1, str);

于 2012-08-27T14:59:09.880 に答える
1

可変個引数マクロ(C99機能)に依存したくない場合は、次のようにすることもできます。

#define syslog my_syslog

static inline int my_syslog(int prio, const char *fmt, ...)
{
    int r;
    va_list ap;
    va_start(ap, fmt);
    r = vprintf(fmt, ap);
    va_end(ap);
    return r;
}

または類似。

于 2012-08-27T15:57:54.943 に答える