如何在C中实现通用宏?

时间:2011-08-31 11:21:05

标签: c types macros generic-programming

FUNC(param);

paramchar *时,请发送至func_string

当它为int时,发送到func_int

我认为可能有一个解决方案,因为变量类型在编译时是已知的。

6 个答案:

答案 0 :(得分:12)

这可以使用C1X,但不能用现行标准。

看起来像这样:

#define cbrt(X) _Generic((X), long double: cbrtl, \
                          default: cbrt, \
                          float: cbrtf)(X)

答案 1 :(得分:11)

变量类型是编译器已知的,但不是预处理器(它将代码简单地视为非结构化文本一个标记流,并且只对其执行简单的替换操作)。所以我担心你无法通过C宏实现这一点。

在C ++中,他们发明了模板来解决这些问题(等等)。

答案 2 :(得分:5)

您可以测试类型的特征。

例如,int可以保留负值,而char*则不能。因此,如果((typeof(param))-1) < 0param未签名:

if (((typeof(param))-1) < 0) {
    do_something_with_int();
} else {
    do_something_with_char_p();
}

编译器显然优化了这一点。

在此处试试:http://ideone.com/et0v1

如果类型有不同的尺寸,这将更容易。例如,如果要编写通用宏而不是可以处理不同的字符大小:

if (sizeof(param) == sizeof(char)) {
    /* ... */
} else if (sizeof(param) == sizeof(char16_t)) {
    /* ... */
} else if (sizeof(param) == sizeof(char32_t)) {
    /* ... */
} else {
   assert("incompatible type" && 0);
}

GCC有一个__builtin_types_compatible_p()内置函数,可以检查类型兼容性:

if (__builtin_types_compatible_p(typeof(param), int)) {
    func_int(param);
} else if (__builtin_types_compatible_p(typeof(param), char*)) {
    func_string(param);
}

在此处试试:http://ideone.com/lEmYE

您可以将其放在宏中以实现您的目标:

#define FUNC(param) ({                                                \
    if (__builtin_types_compatible_p(typeof(param), int)) {           \
        func_int(param);                                              \
    } else if (__builtin_types_compatible_p(typeof(param), char*)) {  \
        func_string(param);                                           \
    }                                                                 \
})

({...})GCC's statement expression,它允许一组语句为右值。

__builtin_choose_expr()内置函数可以选择要编译的表达式。使用__builtin_types_compatible_p,如果param的类型与intchar*不兼容,则允许在编译时触发错误:(在这种情况下编译somehting无效)

#define FUNC(param)                                                        \ 
    __builtin_choose_expr(__builtin_types_compatible_p(typeof(param), int) \ 
        , func_int(param)                                                  \ 
        , __builtin_choose_expr(__builtin_types_compatible_p(typeof(param), char*) \ 
            , func_string(param)                                           \ 
            , /* The void expression results in a compile-time error       \ 
                 when assigning the result to something.  */               \ 
            ((void)0)                                                      \ 
        )                                                                  \ 
    )

这实际上是__builtin_choose_expr docs的一个稍微修改过的例子。

答案 3 :(得分:4)

在C89 / ANSI C中不可能运行时间检查类型,但是gcc有一个扩展允许它。如果我记得,那些类型或类似的东西。我曾经在Linux内核中看到过它。

kernel.h中:

#define min(x, y) ({                \
typeof(x) _min1 = (x);          \
typeof(y) _min2 = (y);          \
(void) (&_min1 == &_min2);      \
_min1 < _min2 ? _min1 : _min2; })

看一下这篇文章:GCC hacks in the Linux kernel

当我第一次看到这个时,我实际上就此问了一个问题:

min macro in kernel.h

我不太清楚你将如何使用它来解决你的问题,但这是值得一看的事情。

答案 4 :(得分:1)

使用宏无法执行此操作。宏的值在编译时被替换,并且没有被解释。他们只是换人。

答案 5 :(得分:1)

变量类型在编译时确实已知,但是在编译之前会进行宏扩展。我建议你实现2个重载函数而不是宏。