如何在C代码中获取变量的类型?

Ami*_*ram 11 c gcc types typeof openmp

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

我想改变OpenMP减少子句的语义.在这一点上,简单地通过调用函数替换源代码中的子句(通过脚本)似乎是最容易的,然后我可以定义函数来实现我想要的缩减语义.例如,我的脚本会转换它

#pragma omp parallel for reduction(+:x)
Run Code Online (Sandbox Code Playgroud)

进入这个:

my_reduction(PLUS, &x, sizeof(x));
#pragma omp parallel for
Run Code Online (Sandbox Code Playgroud)

在哪里,我早些时候(说)

enum reduction_op {PLUS, MINUS, TIMES, AND,
  OR, BIT_AND, BIT_OR, BIT_XOR, /* ... */};
Run Code Online (Sandbox Code Playgroud)

my_reduction签名

void my_reduction(enum reduction_op op, void * var, size_t size);
Run Code Online (Sandbox Code Playgroud)

除其他外,my_reduction必须像程序员最初预期的那样将加法运算应用于约简变量.但我的功能无法知道如何正确地做到这一点.特别是,尽管它知道operation(PLUS)var的类型,原始变量()的位置以及变量类型的大小,但它不知道变量的类型本身.特别是,它不知道是否var具有整数或浮点类型.从低级别POV来看,这两类类型的加法操作完全不同.

如果只有typeofGCC支持的非标准运算符可以像sizeof一样工作 - 返回某种类型的变量 - 我可以轻松地解决这个问题.但是typeof并不像sizeof:它只能在l值声明中使用.

现在,编译器显然在完成生成可执行代码之前就知道了x的类型.这让我想知道我是否可以某种方式利用GCC的解析器,只是获取x类型并将其传递给我的脚本,然后再一次运行GCC来编译我修改过的源代码.那么宣布就足够简单了

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

并且my_reduction可以在解除引用和应用运算符之前适当地进行转换.

正如您所看到的,我正在尝试在C中创建一种"调度"机制.为什么不使用C++重载?因为我的项目限制我使用C编写的遗留源代码.我可以使用脚本自动更改代码,但我无法将其重写为其他语言.

谢谢!

Cir*_*四事件 9

C11 _Generic

这不是一个直接的解决方案,但如果您耐心地编码所有类型,它确实可以让您实现所需的结果:

#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);
}
Run Code Online (Sandbox Code Playgroud)

编译并运行:

gcc -std=c11 a.c
./a.out
Run Code Online (Sandbox Code Playgroud)

在这个答案中可以找到一个很好的起点.

在Ubuntu 17.10,GCC 7.2.0中测试.GCC仅在4.9中增加了支持.


jok*_*007 5

可以使用sizeof函数来确定类型,将未知类型的变量设为var。然后

if(sizeof(var)==sizeof(char))
        printf("char");
    else if(sizeof(var)==sizeof(int))
        printf("int");
    else if(sizeof(var)==sizeof(double))
        printf("double");
Run Code Online (Sandbox Code Playgroud)

当两个或多个主要类型可能具有相同的大小时,就会导致并发症。

  • 请不要这样做。许多类型具有相同的大小,这很容易导致难以发现的错误。 (14认同)

Bas*_*tch 3

GCC提供了typeof扩展。它不是标准的,但足够常见(其他几个编译器,例如 clang/llvm,都有它)。

您也许可以考虑通过使用MELT (一种用于扩展 GCC 的领域特定语言)扩展来自定义 GCC ,以满足您的目的。