web-dev-qa-db-ja.com

printf()を関数またはマクロにラップする方法は?

これはインタビューの質問に少し似ていますが、実際には実際的な問題です。

私は組み込みプラットフォームで作業しており、それらの機能に相当するもののみを利用できます。

  • printf()
  • snprintf()

さらに、printf()実装(および署名)は近い将来変更される可能性が高いため、後で移行しやすくするために、別のモジュールに呼び出す必要があります。

それらを考慮して、ロギング呼び出しをいくつかの関数またはマクロでラップできますか?目標は、私のソースコードがTHAT_MACRO("Number of bunnies: %d", numBunnies);を1000箇所で呼び出すことですが、上記の関数の呼び出しは1箇所でしか見られません。

コンパイラ:arm-gcc -std = c99

27
Vorac

C99を使用できるため、 variadic macro でラップします。

#define TM_PRINTF(f_, ...) printf((f_), __VA_ARGS__)
#define TM_SNPRINTF(s_, sz_, f_, ...) snprintf((s_), (sz_), (f_), __VA_ARGS__)

vprintfまたはそれに類するものがあるとは言わなかったからです。そのようなものがある場合は、Sergey Lが彼の答えで提供したような関数でラップすることができます。


編集:

上記のTM_PRINTFは、空のVA_ARGSリストでは機能しません。少なくともGCCでは、次のように記述できます。

#define TM_PRINTF(f_, ...) printf((f_), ##__VA_ARGS__)

2つの##記号は、__VA_ARGS__が空の場合、それらの前にある余分なコンマを削除します。

34
ldav1s

これを行うには2つの方法があります。

  1. Variadricマクロ

    #define my_printf(...) printf(__VA_ARGS__)
    
  2. va_argsを転送する関数

    #include <stdarg.h>
    #include <stdio.h>
    
    void my_printf(const char *fmt, ...) {
        va_list args;
        va_start(args, fmt);
        vprintf(fmt, args);
        va_end(args);
    }
    

vsnprintfvfprintf、およびstdioで考えられるものもあります。

53
Sergey L.

呼び出しをtwo括弧で囲む必要がある場合は、次のようにできます。

#define THAT_MACRO(pargs)    printf pargs

次にそれを使用します:

THAT_MACRO(("This is a string: %s\n", "foo"));
           ^
           |
          OMG

これは、プリプロセッサの観点から、引数のリスト全体が1つのマクロ引数になり、括弧で置き換えられるため、機能します。

これは単純なことよりも優れています

#define THAT_MACRO printf

それを定義することができるので:

#define THAT_MACRO(pargs)  /* nothing */

これはマクロ引数を「使い果たし」、コンパイルされたコードの一部になることはありません。

[〜#〜] update [〜#〜]もちろん、C99ではこの手法は廃止されており、変数マクロを使用して満足しているだけです。

10
unwind
_#define TM_PRINTF(f_, ...) printf((f_), ##__VA_ARGS__)
_

_##_トークンは、使用法TM_PRINTF("aaa");を有効にします

9
Felipe Lavratti
_#define PRINTF(...) printf(__VA_ARGS__)
_

これは次のように機能します。

パラメーター化されたマクロPRINTFを定義して(最大)無限の引数を受け入れ、PRINTF(...)からprintf(__VA_ARGS__)に前処理します。 ___VA_ARGS___は、指定された引数を示すためにパラメーター化されたマクロ定義で使用されます(無限引数に名前を付けることはできないのですか?)。

3
EKons

限られた図書館?組み込みシステム?できるだけ多くのパフォーマンスが必要ですか?問題ない!

この質問 に対するこの回答で示されているように、アセンブリ言語を使用して、VA_LISTを受け入れない関数をラップし、わずかなコストで独自のvprintfを実装できます!

これは機能しますが、ほぼ確実に必要なパフォーマンスと抽象化をもたらしますが、おそらく Clibc の一部をスライスすることで、より多くの機能を備えた標準ライブラリを取得することをお勧めします。このようなソリューションは、すべてのサイクルを絶対に必要としない限り、アセンブリを使用するよりも、より移植性があり、全体的に有用な答えになるはずです。

結局、そのようなプロジェクトが存在する理由です。

2
Alice