2011-03-29 8 views
16

、私はそれには何も送信することができ、そしてそれを印刷することができどのようにタイプを指定せずにC言語で値を出力できますか?C++の "cerr <<(A)<< endl" C++で

#define DEBUG(A) cerr << (A) << endl; 

を持ちます。しかし、Cでは%d、%c、%sなどで型を指定する必要がありますが、その型を常時書きたくないので、cerrのようにfprintfを使います。どうやってやるの?例えば

:C

#define DEBUG(A) X // X is what I want to write 
... 
// in function, when I put 
DEBUG(5);   // I just want to print 5 
// or, with same statement, when I say 
DEBUG('a');  // output : a 
+0

本当に 'endl'を使いたいですか?それはプログラムを本当に減速させるストリームのフラッシュを引き起こします。 –

+1

補足として、関数のような形のマクロを書くときの標準的な習慣は、式全体にかっこを入れることです。 – Lundin

+5

@mattieu:はい、彼は 'endl'を使っています:プログラムを遅くするためのデバッグで。そして、プログラムがそれを実行するときに、コンソール上の各行を見たいとします。フラッシングしないということは、あなたがたった今印刷したものを見ない*時には。それはデバッグを妨げる。 – towi

答えて

30

では、としては、例えば、少し楽にGNU C Language Extensions

#define DEBUG(x)             \ 
    ({                \ 
    if (__builtin_types_compatible_p (typeof (x), int))   \ 
     fprintf(stderr,"%d\n",x);        \ 
    else if (__builtin_types_compatible_p (typeof (x), char)) \ 
     fprintf(stderr,"%c\n",x);        \ 
    else if (__builtin_types_compatible_p (typeof (x), char[])) \ 
     fprintf(stderr,"%s\n",x);        \ 
    else               \ 
     fprintf(stderr,"unknown type\n");      \ 

    }) 

これらは罰金です:

DEBUG("hello"); //prints hello 
DEBUG(11110); //prints 11110 

しかし、文字のために、あなたがそうでなければ、その種類は「INT」になり、左辺値でそれを使用する必要があります:Cで

char c='A'; 
DEBUG(c); // prints A 
DEBUG('A'); // prints 65 
+2

'endl'と同じ効果を得るために' fflush(stderr); 'をマクロの最後に追加したいでしょう。 –

+2

stderrは実際にはバッファされていないので、fflushは不要です。そして、stdoutはラインバッファリングされているので、その場合は\ nで処理されます。 –

+0

最後に、有用なデータを得るために飛ぶ機会を与えるために、 '&x'から' sizeof(x) 'バイトを' write'するのはどうでしょうか? –

14

にあなたが望む方法でfprintf()を使用することはできません。ようこそCへ。

C++ I/Oストリーム演算子は型保証されており、演算子オーバーロードを使用して魔法を実現しています。これはC言語では利用できませんので、安全ではない形式の文字列へのアプローチが必要です。

10

原則として、Cにはオーバーロード機構がないため、できません。

#define DEBUG_INT(x) fprintf(stderr, "%d\n", (x)) 
#define DEBUG_CHAR(x) fprintf(stderr, "%c\n", (x)) 
8

は、変換仕様を取り除く方法はありませんが、あなたはC99コンパイラを持っている場合、あなたは__VA_ARGS__を使用して、それを行うことができます。

あなたは、しかし、のようないくつかのマクロを定義することができますあなたが使用することができます

#include <stdio.h> 

#define DEBUG(fmt, ...) fprintf(stderr, (fmt), __VA_ARGS__) 

int main(void) { 
    int foo = 42; 
    char *t = "foobar"; 
    DEBUG("%s:%d\n", t, foo); 
    return 0; 
} 
+3

それよりも簡単です:プログラムから直接血まみれのfprintf()を呼び出してください:) – Lundin

+0

@Konstantin:その '_Generic'キーワードのリファレンスはありますか? – pmg

+0

申し訳ありませんが、それはC99ではなく、新しい標準ドラフトのものです。 –

0

、あなたが確実の種類を判別することはできませんオブジェクト。したがって、ジェネリックプログラミングをサポートするためのメカニズムを導入する必要があります。情報を入力し保持する構造体のすべてのオブジェクトを囲む:

enum {type_int, type_double, type_string, /* ... */ } type_t; 
struct { 
     type_t type; 
     void *obj; 
} generic_type; 

を今、あなたは((generic_type)my_object).typeを切り替えることができます。これはおそらくあなたが探しているものではありません。



しかし、マクロの引数が文字列リテラルまたは何か他のものであるかどうかを伝えるために簡単なトリックがあります。マクロは文字「#」を引用すると、あなたは文字列にマクロ引数を変えることができます:今、あなたは次の操作を行うことができます

#define DEBUG(x) if (#x[0] == '"') printf("%s\n", x); else printf("%d\n", x) 

:下側に

DEBUG("foo bar"); // prints "foo bar" 
DEBUG(23);   // prints "23" 

を、これはあなたをさせません例えば、 intおよびfloatである。さらに、ポインタ・ツー・文字は文字列として認識されていません。いくつかのマシンで

char *foo = "bar"; 
DEBUG(foo);  // prints the value of foo, not the string pointed to by foo 

double salary; 
DEBUG(salary);  // prints (int)salary, not (double)salary 

sizeof(double) != sizeof(int)。これはマクロ引数の異なる型をさらに区別するのに役立ちますが、確かに移植性がありません。



は、一般的に言って、あなたはまた、移植性を維持しながら、完全にジェネリックプログラミングのサポートに向けたいくつかの深刻な努力をせずにこの問題を解決することはできません。

私のアドバイス:書式指定子を使用するだけです。代わりに__VA_ARGS__を使用しての

0

、あなたは単に次の操作を実行できます。組み込みの方法GCCとは異なり

#define DEBUG(x...) fprintf(stderr, x) 

、この方法では、あなたはミックス・アンド・マッチすることができます - あなたは「文字列を印刷することができます= "、一度に1つのタイプの代わりに。また、このようにしてサイズや型の非互換性に陥ることはありません.fprintfと基本的に同じですが、ビルド時に除外することはできません。

関連する問題