简体   繁体   English

如何在不指定类型的情况下在C中打印值,就像在C ++中使用“cerr <<(A)<< endl”一样?

[英]How can I print values in C without specifying their types, like done with “cerr << (A) << endl” in C++?

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 . 但是,在C中,我必须用%d,%c或%s等指定它的类型。但我不想一直写它的类型,我想使用类似cerr fprintf How can I do that? 我怎样才能做到这一点?

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

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" : 但对于字符,你应该使用左值,否则它的类型将是“int”:

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

You can't use fprintf() in the way you want. 你不能以你想要的方式使用fprintf() Welcome to C. 欢迎来到C.

C++ I/O stream operators are typesafe and use operator overloading to achieve their magic. C ++ I / O流运算符是类型安全的,并使用运算符重载来实现它们的魔力。 That's not available in C so you have to stick to unsafe format string approaches. 这在C中不可用,因此您必须坚持使用不安全的格式字符串方法。

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))

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;
}

In C, you cannot reliably determine the type of an object. 在C中,您无法可靠地确定对象的类型。 Hence, you'd have to introduce some mechanism to support generic programming, eg enclosing all objects in a structure which holds type information: 因此,您必须引入一些支持泛型编程的机制,例如将所有对象封装在包含类型信息的结构中:

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 . 现在,您可以切换((generic_type)my_object).type This is probably not what you're looking for. 这可能不是你想要的。



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 eg int s and float s. 在缺点方面,这不会让你区分例如int s和float s。 Furthermore, pointers-to-char are not recognized as strings: 此外,指向char的指针不被识别为字符串:

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) . 在某些机器上, sizeof(double) != sizeof(int) This might help to further distinguish between the different types of your macro arguments, but it's certainly not portable. 这可能有助于进一步区分不同类型的宏参数,但它肯定不可移植。



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. 我的建议:简单地习惯格式说明符。

Instead of using the __VA_ARGS__ , you can just simply do the following: 您可以只执行以下__VA_ARGS__ ,而不是使用__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. 与GCC内置方法不同,此方法允许您混合匹配 - 您可以打印“string =”,而不是一次只打印一种类型。 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! 您也不会以这种方式遇到大小和类型不兼容 - 它与fprintf基本相同,除非能够在构建时被排除!

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM