假设我想要一个可以在任何类型上工作的c宏。
我使用gcc编译器(>=4.6),可以使用gnu99宏。

//code...
any_type_t *retVal = function_that_runs_very_long_time(a, b, &&c, **d, &e, *f);
//other code...

定时器宏的用法可以如下所示
//code...
any_type_t *retVal =
    TIMER(
          function_that_runs_very_long_time(a, b, &&c, **d, &e, *f),
          "TIMING FOR VALUE <%d, %d>", a, b
         );
//other code...

所以定时器必须返回给定函数的值并打印其运行的持续时间。
返回类型为void的函数有问题。
很明显,我可以有两个宏,比如timer_type和timer_void,但是我想使用任何返回值的一对一函数。
谢谢你的建议。
此计时器宏的编辑示例
#define TIMER(expr, fmt_msg, ...)                           \
({                                                          \
    struct timeval before, after;                           \
    uint64_t time_span;                                     \
    int time_span_sec, time_span_usec;                      \
    gettimeofday(&before, NULL);                            \
    typeof(expr) _timer_expr__ = (expr);                    \ // <- static if?
    gettimeofday(&after, NULL);                             \
    time_span = (after.tv_sec * 1000000 + after.tv_usec)    \
              - (before.tv_sec * 1000000 + before.tv_usec); \
    time_span_sec  = time_span / 1000000;                   \
    time_span_usec = time_span % 1000000;                   \
    TRACE(fmt_msg "\n%s : %d.%d seconds",                   \
          #expr, time_span_sec, time_span_usec, ...);       \
    _timer_expr__;                                          \
})

最佳答案

真是个有趣的问题,大人!
经过几次实验,我找到了一种使用gcc的__builtin_types_compatible_p and __builtin_choose_expr内部函数的解决方案。
__builtin_types_compatible_p
引用GCC手册:
内置功能:int __builtin_types_compatible_p (type1, type2)
您可以使用内置函数__builtin_types_compatible_p来确定两种类型是否相同。
如果类型1type1的非限定版本(属于类型,而不是表达式)兼容,则此内置函数返回type2,否则返回0。此内置函数的结果可用于整数常量表达式。
此内置函数忽略顶级限定符(例如,constvolatile)。例如,int等同于const int
所以这里是我们如何检查“voidness”。

#define __type_is_void(expr) __builtin_types_compatible_p(typeof(expr), void)

__builtin_choose_expr
内置功能:type __builtin_choose_expr (const_exp, exp1, exp2)
您可以使用内置函数__builtin_choose_expr根据常量表达式的值计算代码。如果整数常量表达式exp1为非零,则此内置函数返回const_exp。否则返回exp2
这个内置函数类似于c中的? :运算符,只是返回的表达式的类型没有被提升规则更改。此外,内置函数不会计算未选择的表达式。例如,如果const_exp计算结果为true,则即使有副作用也不会计算exp2
如果返回exp1,则返回类型与exp1的类型相同。同样,如果返回exp2,则其返回类型与exp2相同。
所以__builtin_choose_expr内在函数类似于编译时计算的“静态开关”。
准备
我不在这里粘贴您的TIMER宏,但我假设它可以将其分为两个版本:一个用于voidexpr另一个用于其他版本。下面是对表达式求值并产生相同类型结果的存根。
#define __DO(expr) \
    ({ typeof(expr) __ret; __ret = (expr); __ret; })

#define __DO_VOID(expr) \
    (void) (expr)

天真的解决方案
现在,我们可以根据表达式的实际类型,在两个实现之间进行静态切换。但事实上,这种天真的解决方案行不通,见下文。
#define DO(expr) \
    __builtin_choose_expr(__type_is_void(expr), \
        __DO_VOID(expr), \
        __DO(expr))  # won't work

尝试通过void表达式编译此代码时会出现以下错误:
test.c:28:9: error: variable or field ‘__ret’ declared void
test.c:28:9: error: void value not ignored as it ought to be

虽然选择了__DO_VOID,但__DO会生成错误。此行为在手册中描述:
…未使用的表达式(exp1exp2取决于const_exp的值)仍可能生成语法错误。这可能会在以后的修订中发生变化。
工作溶液
诀窍是用一些非void值替换原来的voidexpr,以便能够编译__DO案例(当expr为void时,这仍然是一个死代码)。
#define __expr_or_zero(expr) __builtin_choose_expr(__type_is_void(expr), 0, (expr))

#define DO(expr) \
    __builtin_choose_expr(__type_is_void(expr), \
        __DO_VOID(expr), \
        __DO(__expr_or_zero(expr))) # works fine!

就是这样!以下是ideone上的完整源代码:http://ideone.com/EFy4pE

08-16 13:15