简体   繁体   English

输入 C 以进行调试的最简单方法

[英]Simplest way to get type in C for debugging purposes

Usually when I need the type in C for something I don't know I'll just print it with a wrong format and see what gcc tells me.通常当我需要 C 中的类型时,我不知道我会以错误的格式打印它,然后看看gcc告诉我什么。 For example:例如:

int printme(int n, ...)
{
    // What type is `va_list` ??
    va_list ap;
    printf("%d", ap);
}

int main(void)
{
    printme("Hi", "There");
}
 > a.c:12:14: warning: format ‘%d’ expects argument of type ‘int’, 
    but argument 2 has type ‘__va_list_tag *’ [-Wformat=]
   printf("%d", ap);

Is there a better way to inspect the type of something for debugging purposes?有没有更好的方法来检查某些东西的类型以进行调试?

Yes, there is a better way, and I'd say, it is the only Right Thing(TM) to do:是的,有一个更好的方法,我想说,这是唯一正确的事情(TM)

Read the source defining the data type.阅读定义数据类型的源。

Generally, C has no way to tell you during run time, what type a value has.一般来说,C 在运行时无法告诉你一个值是什么类型。 Other languages have "reflection" or a similar feature, but not C.其他语言具有“反射”或类似功能,但没有 C。

To simplify this task, you might like to use a tool that reads all source files and header files of your project, and that gives you an overview.为了简化此任务,您可能希望使用一个工具来读取项目的所有源文件和 header 文件,并为您提供概览。 However, software recommendations are out of scope of this site.但是,软件推荐不在此站点的 scope 中。

Type of va_list is a compiler implementation defined type. va_list的类型是编译器实现定义的类型。 Basically is a type necessary to be able to do the following, when used with these macros:当与这些宏一起使用时,基本上是一种能够执行以下操作的类型:


void f(int a, int b, double fmt, ...)
{
    va_list p;

    va_start(p, fmt);  /* save the address in the stack of parameter `fmt` */
    ....
    SOME_TYPE q = va_arg(p, SOME_TYPE);
    ....
    SOME_TYPE q = va_arg(p, SOME_TYPE);
    ....
    va_end(p);
}

which is how the thing is prepared to work.这就是事情准备工作的方式。 Old implementations used a void *[1] type (an array of one pointer to void element --- or even a char *[] pointer, in very old implementations) to store there the reference to the first parameter, which was moved by the sizeof (SOME_TYPE) when va_arg macro was called ( SOME_TYPE is not restricted to be always the same type, you can change the type in each call to va_arg ).旧实现使用void *[1]类型(一个指向 void 元素的指针的数组 --- 甚至是char *[]指针,在非常旧的实现中)来存储对第一个参数的引用,该参数由调用va_arg宏时的sizeof (SOME_TYPE)SOME_TYPE不限于始终为同一类型,您可以在每次调用va_arg时更改类型)。 But today, it is normally implemented as some intrinsic function of the compiler, as some knowledge of how the stack is incremented/decremented or how the compiler handlers register passed parameters is necessary to implement it.但是今天,它通常被实现为编译器的一些内在 function,因为需要了解堆栈如何递增/递减或编译器处理程序如何注册传递的参数来实现它。

If you don't get so complex, and you have to know eg how the type dev_t is defined (this is a posix type, not an ansi-c type, because it is the type that a posix type uses to represent a device in the kernel) and you need to print it, then you can always cast it to an int (or a long ) and use that in your printf format.如果您没有变得如此复杂,并且您必须知道例如dev_t类型是如何定义的(这是 posix 类型,而不是 ansi-c 类型,因为它是 posix 类型用来表示设备的类型内核)并且您需要打印它,然后您始终可以将其转换为int (或long )并以printf格式使用它。

Historically there have been some approaches to this (like using z modifier in the format string to print a size_t or ssize_t data type) but not every compiler has them implemented and this force you to stick on one of the last standards.从历史上看,有一些方法可以解决这个问题(比如在格式字符串中使用z修饰符来打印size_tssize_t数据类型),但并不是每个编译器都实现了它们,这迫使你坚持最后的标准之一。 If you want to produce portable code, the casting mechanism is probably the best, if you know a priori that the value is going to fit in the type you use to print.如果您想生成可移植的代码,那么强制转换机制可能是最好的,前提是您先验地知道该值将适合您用于打印的类型。

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

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