如何获取C代码中的变量类型? [英] How to get the type of a variable in C code?

查看:151
本文介绍了如何获取C代码中的变量类型?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

有没有什么办法可以在C中自动发现变量的类型,或者通过程序本身的某种机制,或者 - 更可能的是 - 通过预编译脚本,使用编译器传递给指出它已经分析了变量并为它们分配了它们的类型?我正在寻找关于此的一般建议。以下是我需要的更多背景以及为什么。



我想更改OpenMP减少子句的语义。此时,只需简单地将源代码中的子句(通过脚本)替换为对函数的调用即可,然后我可以定义函数来实现我想要的简化语义。例如,我的脚本会将此转换为

  #pragma omp parallel for reduction(+:x)

放入此内容:

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

其中,之前,我有(说)

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

my_reduction 有签名

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

除此之外, my_reduction 必须按照程序员最初的设想将加法运算应用于还原变量。但我的功能无法知道如何正确执行此操作。特别是,虽然它知道操作的类型( PLUS ),但原始变量( var )的位置,和变量类型的大小,它不知道变量的类型本身。特别是,它不知道 var 是否具有整型或浮点型。从低级POV开始,这两类类型的加法操作是完全不同的。



如果只有非标准运算符 typeof 会以sizeof的方式工作 - 返回某种类型的变量 - 我可以很容易地解决这个问题。但是typeof并不像sizeof:它显然只能在l值声明中使用。



现在,编译器显然知道它之前的x的类型完成生成可执行代码。这让我想知道我是否可以以某种方式利用GCC的解析器,只是为了获取 x 的类型并将其传递给我的脚本,然后再一次运行GCC,编译我更改的源代码。这将足够简单地声明

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

my_reduction 可以在解引用应用运算符。

正如你所看到的,我试图在C中创建一种调度机制。为什么不使用C ++重载呢?因为我的项目限制了我使用C语言编写的原始代码。我可以使用脚本自动修改代码,但我不能将其重写为其他语言。



谢谢!

解决方案

C11 _Generic



不是一个直接的解决方案,但它确实可以让你达到所期望的结果,如果你耐心地编码所有类型的话:

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

#define typename(x)_Generic((x),\
int:int,\
float:float,\
默认: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);
}

编译并使用:

  gcc -std = c11 ac 
./a.out

有很多类型的好起点可以在这个答案中找到。



在Ubuntu 17.10,GCC 7.2.0中测试。 GCC只支持4.9。


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!

解决方案

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.

这篇关于如何获取C代码中的变量类型?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆