使用宏进行类型泛型编程:确定类型的技巧?

时间:2010-12-02 03:45:56

标签: c generics macros c-preprocessor

可以在 C 中将某些类型的泛型函数作为宏来执行,例如:

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

只要x是浮点类型,这(大多数情况下)就可以正常工作。

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

5 个答案:

答案 0 :(得分:3)

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

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

答案 1 :(得分:3)

您可以检测表达式是整数表达式还是char*表达式,至少在指向uintptr_t的指针转换得很明确的架构上是这样的:

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

这将检测X是否是指向T类型sizeof(T) > 1的指针。这不适用于void*和其他极端情况。而且因为X被评估了两次,你必须注意副作用。

如果X类型为signed int,则可以避免整数溢出问题,您可以将(X)替换为

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

这保证了如果X是整数表达式,则它将是uintmax_t类型。然后+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)

答案 2 :(得分:2)

您的结果不是真的类型泛型,因为无论传递什么类型的参数,结果始终为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 :(得分:1)

为此目的,C11 standard添加了_Generic关键字。

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

您的示例可以使用此关键字编写,如下所示:

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

version 4.9以来,GCC为此关键字提供支持。

答案 4 :(得分:0)

可以使用某种类型检查系统,但它实际上是C中的一个kludge。

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

相关问题