如何在不指定类型的情况下在C中打印值,比如在c++中使用“cerr

时间:2022-09-06 20:06:40

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.ints and floats. 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.ints and floats. 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相同,但是可以在构建时被排除!