2010-12-02 66 views
7

这是可以做到的某些类型的类型泛型函数作为宏在Ç,例如之类的东西:使用宏进行类型泛型编程:使用技巧来确定类型?

#define SQRT(x) (sizeof(x) == sizeof(float) ? sqrtf((x)) : \ 
       sizeof(x) == sizeof(double) ? sqrt((x)) : \ 
       sqrtl((x))) 

此作品(大部分)作为只要x是浮点型的预期。

但是,如果我想要一个类型通用宏,可以采取一个整数类型或指针类型,它可能具有相同的大小。有一种聪明的方法来测试宏参数是一个整数还是一个指针?整数与浮点类型有什么关系?

回答

3

编号宏不知道是什么类型。他们执行#define的文字复制和粘贴。类型安全在这里根本不存在。

从任何有意义的意义上说C不是一种强类型语言。如果你想要一些类型安全的小东西,可以使用C++,在那里你可以用模板和函数重载来完成一些工作。

+0

宏并不是天生就知道的,但有时候会有技巧。例如,`((0 *(x)-1)<0)`可以确定是否签署了x(假设x的转换等级为int或更高)。 – 2010-12-02 04:06:57

0

这是可能有某种类型检查系统,但它确实是在C的杂牌

glib做到这一点;你可以看看他们是怎么做的,或者可以自己使用它(无论如何它都是一个漂亮的C库)。

3

你的结果是不是真的泛型,因为结果总是long double不管是什么类型的参数传递的 - 的?:结果类型时,第二个和第三个操作数是算术类型是类型会将通常的算术转换应用于这些操作数。为了让这样,你可以使用GCC的typeof扩展:

#define SQRT(x) (__typeof__ (x))(sizeof(x) == sizeof(float) ? sqrtf((x)) : \ 
       sizeof(x) == sizeof(double) ? sqrt((x)) : \ 
       sqrtl((x))) 

整数与浮点还可以使用typeof完成:

(__typeof__ (X))1.1 == 1 

我不能想办法做整型与指针。虽然在this page上描述的技术非常有趣。

3

表达式是否其中铸造由指针uintptr_t被很好地定义的整数表达式或char*表达,至少在架构可在检测:

#define INT_OR_CHARP(X) (((uintptr_t)((X)+1) - (uintptr_t)(X)) == 1) 

这将检测是否X是一个指向键入Tsizeof(T) > 1。这不适用于void*和其他角落案件。并且因为X被评估了两次,所以您必须注意副作用。

为了避免整数溢出问题,如果X是e.g类型的signed int您可以用

(1 ? (X) : (uintmax_t)0) 

这保证如果X是一个整数表达式,这将是uintmax_t类型的替代(X)。然后+1可能会环绕,但结果总是很好定义,并且两个部分之间的差异始终是1。如果X是指针表达式,那么这是因为任何值为0的恒定整数表达式也是空指针常量

在总这给出

#define INT_OR_CHARP(X) (((uintptr_t)((1 ? (X) : (uintmax_t)0)+1) - (uintptr_t)(1 ? (X) : (uintmax_t)0)) == 1) 
+0

我不明白'(1?(X):(uintmax_t)0)`是有用的。这是``:`操作符强制类型的某种伎俩吗?无符号类型也不会溢出。 – 2010-12-02 13:55:55

1

C11 standard加入用于此目的的_Generic关键字。

它的工作方式类似于表达式类型的switch语句。

您的例子可以使用此关键字这样写:

#define SQRT(X) _Generic((X), 
    float: sqrtf, \ 
    double: sqrt, \ 
    default: sqrtl \ 
)(X) 

GCC提供自version 4.9此关键字的支持。