繁体   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++?

在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

您可以使用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");                        \

  })

这些很好:

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

但对于字符,你应该使用左值,否则它的类型将是“int”:

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

你不能以你想要的方式使用fprintf() 欢迎来到C.

C ++ I / O流运算符是类型安全的,并使用运算符重载来实现它们的魔力。 这在C中不可用,因此您必须坚持使用不安全的格式字符串方法。

原则上,你不能,因为C没有重载机制。

但是,您可以定义许多宏,例如:

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

没有办法摆脱转换规范,但是如果你有一个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;
}

在C中,您无法可靠地确定对象的类型。 因此,您必须引入一些支持泛型编程的机制,例如将所有对象封装在包含类型信息的结构中:

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 s和float s。 此外,指向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

在某些机器上, sizeof(double) != sizeof(int) 这可能有助于进一步区分不同类型的宏参数,但它肯定不可移植。



一般来说,如果不对通用编程支持做出一些认真努力同时保持可移植性,您将无法完全解决此问题。

我的建议:简单地习惯格式说明符。

您可以只执行以下__VA_ARGS__ ,而不是使用__VA_ARGS__

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

与GCC内置方法不同,此方法允许您混合匹配 - 您可以打印“string =”,而不是一次只打印一种类型。 您也不会以这种方式遇到大小和类型不兼容 - 它与fprintf基本相同,除非能够在构建时被排除!

暂无
暂无

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

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