简体   繁体   中英

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. 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:

Read the source defining the data type.

Generally, C has no way to tell you during run time, what type a value has. Other languages have "reflection" or a similar feature, but not 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. However, software recommendations are out of scope of this site.

Type of va_list is a compiler implementation defined type. 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 ). 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.

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.

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

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

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