GCC4.7+中如何替代C11中的_Generic

C11标准中,一个非常重大的特性更新就是增加了Generic Selection这个特性。这个特性能使得C11支持轻量级的泛型编程,使得可以把一组具有不同类型而却有相同功能的函数抽象为一个接口。

对于_Generic的使用可参见俺这篇博文——http://www.cnblogs.com/zenny-chen/archive/2012/09/20/2695381.html


由于GCC至今还没有支持C11标准的Generic Selection,不过GCC似乎从4.0版本开始就支持了一些内建的编译时函数(这些函数类似于sizeof),包括比较常见的typeof。这里,我们通过组合使用__builtin_choose_expr以及__builtin_types_compatible_p就可实现C11的Generic Selection功能。

我们先看一下__builtin_choose_expr的原型:

type __builtin_choose_expr (const_exp, exp1, exp2)

这里要注意的是这个函数的第一个参数必须是常量表达式,因为之前我已经说过,它属于编译时行为,而非运行时行为,跟sizeof和typeof一样。这个函数是一个谓词函数,如果const_expr的结果非0,那么生成exp1,且返回类型type也与exp1表达式的类型一致;否则生成exp2,并且返回类型type也与exp2的类型一致。由于是编译时行为,因此exp1与exp2表达式所产生的目标代码是互斥的,生成了exp1就不会存在exp2。下面举一个简单例子:

int main(void)
{
    (void)__builtin_choose_expr(100 < 1000, puts("OK"), puts("NG"));

    int a = __builtin_choose_expr(sizeof('a') == 1, "YES", 100);
    printf("The value is: %d
", a);
}


然后,我们再看一下编译时内建函数__builtin_types_compatible_p,其原型为——

int __builtin_types_compatible_p (type1, type2)

这个函数是比较type1与type2两个类型(注意,这里是类型,而不是表达式),如果两个类型的非限定版本相兼容,那么返回1,否则返回0。这里也举个简单的例子:

int main(void)
{
    int r = __builtin_types_compatible_p(typeof('a'), char);
    printf("result 1 is: %d
", r);
    
    r = __builtin_types_compatible_p(typeof('a'), const int);
    printf("result 2 is: %d
", r);
}


好。介绍完了这两个编译时内建函数之后,我们就来看看如何将它们组合起来以实现C11 Generic Selection的功能:

int main(void)
{
    _Generic('a', int:puts("WOW"), char:puts("Ja~~"), default:puts("Oui~~"));

    // equivalent
    (void)__builtin_choose_expr(__builtin_types_compatible_p(typeof('a'), int), puts("WOW"),
                                __builtin_choose_expr(__builtin_types_compatible_p(typeof('a'), char), puts("Ja~~"), puts("Oui~~")));
}

这里要注意的是,使用这些内建函数必须开启GNU规范,4.7以上版本的GCC可直接用C11标准了,开启方法为:在命令选项中添加-std=gnu11

原文地址:https://www.cnblogs.com/zenny-chen/p/3303560.html