In C++, having
在c++中,
#define DEBUG(A) cerr << (A) << endl;
I can send anything to it, and it can print it. However, in C, I must specify its type with %d, %c or %s etc. But I don't want to write its type all time, I want to use fprintf
like cerr
. How can I do that?
我可以发送任何东西给它,它可以打印出来。但是,在C中,我必须用%d、% C或%s等来指定它的类型。但是我不想一直写它的类型,我想使用fprintf,比如cerr。我怎么做呢?
For example: in C
例如:在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
6 个解决方案
#1
30
You can use GNU C Language Extensions :
您可以使用GNU C语言扩展:
#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"); \
})
These are fine:
这些都很好:
DEBUG("hello"); //prints hello
DEBUG(11110); //prints 11110
But for chars, you should use it with lvalue, otherwise its type will be "int" :
但是对于chars,你应该将它与lvalue一起使用,否则它的类型将是“int”:
char c='A';
DEBUG(c); // prints A
DEBUG('A'); // prints 65
#2
14
You can't use fprintf()
in the way you want. Welcome to C.
不能以您希望的方式使用fprintf()。欢迎来到C。
C++ I/O stream operators are typesafe and use operator overloading to achieve their magic. That's not available in C so you have to stick to unsafe format string approaches.
c++ I/O流操作符是类型afe,使用操作符重载来实现它们的神奇。这在C语言中是不可用的,所以您必须坚持使用不安全的格式字符串方法。
#3
10
In principle, you can't, as C don't have an overloading mechanism.
原则上,你不能,因为C没有重载机制。
You can, however, define a number of macros like:
但是,您可以定义一些宏,如:
#define DEBUG_INT(x) fprintf(stderr, "%d\n", (x))
#define DEBUG_CHAR(x) fprintf(stderr, "%c\n", (x))
#4
8
There is no way to get rid of the conversion specifications, but if you have a C99 compiler, you can use __VA_ARGS__
and make it a little easier, as, for example, in
没有办法摆脱转换规范,但是如果您有一个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;
}
#5
0
In C, you cannot reliably determine the type of an object. Hence, you'd have to introduce some mechanism to support generic programming, e.g. enclosing all objects in a structure which holds type information:
在C语言中,您不能可靠地确定对象的类型。因此,您必须引入一些机制来支持泛型编程,例如,将所有对象封装在一个包含类型信息的结构中:
enum {type_int, type_double, type_string, /* ... */ } type_t;
struct {
type_t type;
void *obj;
} generic_type;
Now, you can switch over ((generic_type)my_object).type
. This is probably not what you're looking for.
现在,您可以切换到(generic_type)my_object .type。这可能不是你想要的。
However, there's a simple trick to tell whether a macro argument is a string literal or something else. With the macro quoting character '#', you can turn a macro argument into a string:
但是,有一个简单的技巧可以告诉宏参数是字符串文字还是其他东西。使用宏引用字符'#',您可以将宏参数转换为字符串:
#define DEBUG(x) if (#x[0] == '"') printf("%s\n", x); else printf("%d\n", x)
Now you can do the following:
现在你可以做以下事情:
DEBUG("foo bar"); // prints "foo bar"
DEBUG(23); // prints "23"
On the downside, this won't let you distinguish between e.g.int
s and float
s. Furthermore, pointers-to-char are not recognized as strings:
缺点是,这不会让您区分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
On some machines, sizeof(double) != sizeof(int)
. This might help to further distinguish between the different types of your macro arguments, but it's certainly not portable.
在某些机器上,sizeof(double) = sizeof(int)。这可能有助于进一步区分不同类型的宏参数,但它肯定不是可移植的。
Generally speaking, you won't be able to completely solve this problem without some serious effort towards generic programming support while also maintaining portability.
一般来说,如果不认真地提供通用编程支持并同时保持可移植性,您将无法完全解决这个问题。
My advice: simply get used to format specifiers.
我的建议是:只需习惯于格式化说明符。
#6
0
Instead of using the __VA_ARGS__
, you can just simply do the following:
不使用__VA_ARGS__,您只需执行以下操作:
#define DEBUG(x...) fprintf(stderr, x)
Unlike the GCC built-in methods, this method allows you to mix-and-match - you can print "string=", instead of just one type at a time. You also won't run into size and type incompatibility this way - it's essentially the same as fprintf, except able to be excluded at build-time!
与GCC内置的方法不同,这个方法允许您混合和匹配—您可以打印“string=”,而不是每次只打印一种类型。您也不会以这种方式遇到大小和类型不兼容性——它本质上与fprintf相同,但是可以在构建时被排除!
#1
30
You can use GNU C Language Extensions :
您可以使用GNU C语言扩展:
#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"); \
})
These are fine:
这些都很好:
DEBUG("hello"); //prints hello
DEBUG(11110); //prints 11110
But for chars, you should use it with lvalue, otherwise its type will be "int" :
但是对于chars,你应该将它与lvalue一起使用,否则它的类型将是“int”:
char c='A';
DEBUG(c); // prints A
DEBUG('A'); // prints 65
#2
14
You can't use fprintf()
in the way you want. Welcome to C.
不能以您希望的方式使用fprintf()。欢迎来到C。
C++ I/O stream operators are typesafe and use operator overloading to achieve their magic. That's not available in C so you have to stick to unsafe format string approaches.
c++ I/O流操作符是类型afe,使用操作符重载来实现它们的神奇。这在C语言中是不可用的,所以您必须坚持使用不安全的格式字符串方法。
#3
10
In principle, you can't, as C don't have an overloading mechanism.
原则上,你不能,因为C没有重载机制。
You can, however, define a number of macros like:
但是,您可以定义一些宏,如:
#define DEBUG_INT(x) fprintf(stderr, "%d\n", (x))
#define DEBUG_CHAR(x) fprintf(stderr, "%c\n", (x))
#4
8
There is no way to get rid of the conversion specifications, but if you have a C99 compiler, you can use __VA_ARGS__
and make it a little easier, as, for example, in
没有办法摆脱转换规范,但是如果您有一个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;
}
#5
0
In C, you cannot reliably determine the type of an object. Hence, you'd have to introduce some mechanism to support generic programming, e.g. enclosing all objects in a structure which holds type information:
在C语言中,您不能可靠地确定对象的类型。因此,您必须引入一些机制来支持泛型编程,例如,将所有对象封装在一个包含类型信息的结构中:
enum {type_int, type_double, type_string, /* ... */ } type_t;
struct {
type_t type;
void *obj;
} generic_type;
Now, you can switch over ((generic_type)my_object).type
. This is probably not what you're looking for.
现在,您可以切换到(generic_type)my_object .type。这可能不是你想要的。
However, there's a simple trick to tell whether a macro argument is a string literal or something else. With the macro quoting character '#', you can turn a macro argument into a string:
但是,有一个简单的技巧可以告诉宏参数是字符串文字还是其他东西。使用宏引用字符'#',您可以将宏参数转换为字符串:
#define DEBUG(x) if (#x[0] == '"') printf("%s\n", x); else printf("%d\n", x)
Now you can do the following:
现在你可以做以下事情:
DEBUG("foo bar"); // prints "foo bar"
DEBUG(23); // prints "23"
On the downside, this won't let you distinguish between e.g.int
s and float
s. Furthermore, pointers-to-char are not recognized as strings:
缺点是,这不会让您区分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
On some machines, sizeof(double) != sizeof(int)
. This might help to further distinguish between the different types of your macro arguments, but it's certainly not portable.
在某些机器上,sizeof(double) = sizeof(int)。这可能有助于进一步区分不同类型的宏参数,但它肯定不是可移植的。
Generally speaking, you won't be able to completely solve this problem without some serious effort towards generic programming support while also maintaining portability.
一般来说,如果不认真地提供通用编程支持并同时保持可移植性,您将无法完全解决这个问题。
My advice: simply get used to format specifiers.
我的建议是:只需习惯于格式化说明符。
#6
0
Instead of using the __VA_ARGS__
, you can just simply do the following:
不使用__VA_ARGS__,您只需执行以下操作:
#define DEBUG(x...) fprintf(stderr, x)
Unlike the GCC built-in methods, this method allows you to mix-and-match - you can print "string=", instead of just one type at a time. You also won't run into size and type incompatibility this way - it's essentially the same as fprintf, except able to be excluded at build-time!
与GCC内置的方法不同,这个方法允许您混合和匹配—您可以打印“string=”,而不是每次只打印一种类型。您也不会以这种方式遇到大小和类型不兼容性——它本质上与fprintf相同,但是可以在构建时被排除!