How to get the type of a variable in C code?

只愿长相守 提交于 2019-12-17 18:55:46

问题


Is there any way that I can discover the type of a variable automatically in C, either through some mechanism within the program itself, or--more likely--through a pre-compilation script that uses the compiler's passes up to the point where it has parsed the variables and assigned them their types? I'm looking for general suggestions about this. Below is more background about what I need and why.

I would like to change the semantics of the OpenMP reduction clause. At this point, it seems easiest simply to replace the clause in the source code (through a script) with a call to a function, and then I can define the function to implement the reduction semantics I want. For instance, my script would convert this

#pragma omp parallel for reduction(+:x)

into this:

my_reduction(PLUS, &x, sizeof(x));
#pragma omp parallel for

where, earlier, I have (say)

enum reduction_op {PLUS, MINUS, TIMES, AND,
  OR, BIT_AND, BIT_OR, BIT_XOR, /* ... */};

And my_reduction has signature

void my_reduction(enum reduction_op op, void * var, size_t size);

Among other things, my_reduction would have to apply the addition operation to the reduction variable as the programmer had originally intended. But my function cannot know how to do this correctly. In particular, although it knows the kind of operation (PLUS), the location of the original variable (var), and the size of the variable's type, it does not know the variable's type itself. In particular, it does not know whether var has an integral or floating-point type. From a low-level POV, the addition operation for those two classes of types is completely different.

If only the nonstandard operator typeof, which GCC supports, would work the way sizeof works--returning some sort of type variable--I could solve this problem easily. But typeof is not really like sizeof: it can only be used, apparently, in l-value declarations.

Now, the compiler obviously does know the type of x before it finishes generating the executable code. This leads me to wonder whether I can somehow leverage GCC's parser, just to get x's type and pass it to my script, and then run GCC again, all the way, to compile my altered source code. It would then be simple enough to declare

enum var_type { INT8, UINT8, INT16, UINT16, /* ,..., */ FLOAT, DOUBLE};
void my_reduction(enum reduction_op op, void * var, enum var_type vtype);

And my_reduction can cast appropriately before dereferencing and applying the operator.

As you can see, I am trying to create a kind of "dispatching" mechanism in C. Why not just use C++ overloading? Because my project constrains me to work with legacy source code written in C. I can alter the code automatically with a script, but I cannot rewrite it into a different language.

Thanks!


回答1:


C11 _Generic

Not a direct solution, but it does allow you to achieve the desired result if you are patient to code all types as in:

#include <assert.h>
#include <string.h>

#define typename(x) _Generic((x), \
    int:     "int", \
    float:   "float", \
    default: "other")

int main(void) {
    int i;
    float f;
    void* v;
    assert(strcmp(typename(i), "int")   == 0);
    assert(strcmp(typename(f), "float") == 0);
    assert(strcmp(typename(v), "other") == 0);
}

Compile and run with:

gcc -std=c11 a.c
./a.out

A good starting point with tons of types can be found in this answer.

Tested in Ubuntu 17.10, GCC 7.2.0. GCC only added support in 4.9.




回答2:


C doesn't really have a way to perform this at pre-compile time, unless you write a flood of macros. I would not recommend the flood of macros approach, it would basically go like this:

void int_reduction (enum reduction_op op, void * var, size_t size);

#define reduction(type,op,var,size) type##_reduction(op, var, size)

...
reduction(int, PLUS, &x, sizeof(x)); // function call

Note that this is very bad practice and should only be used as last resort when maintaining poorly written legacy code, if even then. There is no type safety or other such guarantees with this approach.

A safer approach is to explicitly call int_reduction() from the caller, or to call a generic function which decides the type in runtime:

void reduction (enum type, enum reduction_op op, void * var, size_t size)
{
  switch(type)
  {
    case INT_TYPE:
      int_reduction(op, var, size);
      break;
    ...
  }
} 

If int_reduction is inlined and various other optimizations are done, this runtime evaluation isn't necessarily that much slower than the obfuscated macros, but it is far safer.




回答3:


You can use sizeof function to determine type , let the variable of unknown type be var. then

if(sizeof(var)==sizeof(char))
        printf("char");
    else if(sizeof(var)==sizeof(int))
        printf("int");
    else if(sizeof(var)==sizeof(double))
        printf("double");

Thou it will led to complications when two or more primary types might have same size .




回答4:


You could also consider customizing GCC with a plugin or a MELT extension for your needs. However, this requires understanding some of GCC internal representations (Gimple, Tree) which are complex (so will take you days of work at least).

But types are a compile-only thing in C. They are not reified.




回答5:


GCC provides the typeof extension. It is not standard, but common enough (several other compilers, e.g. clang/llvm, have it).

You could perhaps consider customizing GCC by extending it with MELT (a domain specific language to extend GCC) to fit your purposes.



来源:https://stackoverflow.com/questions/9156226/how-to-get-the-type-of-a-variable-in-c-code

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!