Din*_*lla 10 c types void compile-time c-preprocessor
让我们说我希望C macro适用于任何类型.我正在使用GCC编译器(> = 4.6)并且可以使用GNU99宏.
//code...
any_type_t *retVal = function_that_runs_very_long_time(a, b, &&c, **d, &e, *f);
//other code...
Run Code Online (Sandbox Code Playgroud)
用于TIMER的宏的用法可以看起来像这样
//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...
Run Code Online (Sandbox Code Playgroud)
因此TIMER必须返回给定函数的值和其运行的打印持续时间.具有void返回类型的函数存在问题.
我显然可以有两个宏,如TIMER_TYPE和TIMER_VOID,但我想使用单一的时间函数与任何返回值.
谢谢你的建议.
编辑此TIMER宏的示例
#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__; \
})
Run Code Online (Sandbox Code Playgroud)
Eld*_*mov 12
多么有趣的问题,恭喜!
几个实验后,我发现它使用的解决方案__builtin_types_compatible_p和__builtin_choose_expr海湾合作委员会的内部函数.
__builtin_types_compatible_p引用GCC手册:
内置功能:
int __builtin_types_compatible_p (type1, type2)您可以使用内置函数
__builtin_types_compatible_p来确定两种类型是否相同.
1如果类型的非限定版本type1和type2(类型,而不是表达式)兼容,0则此内置函数返回.此内置函数的结果可用于整型常量表达式.此内置函数忽略顶级限定符(例如
const,volatile).例如,int相当于const int.
所以这就是我们如何检查" voidness".
#define __type_is_void(expr) __builtin_types_compatible_p(typeof(expr), void)
Run Code Online (Sandbox Code Playgroud)
__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宏,但我认为它能够将它分成两个版本:一个用于void expr,另一个用于其余版本.这里只是存根,它们评估表达式并产生相同类型的结果.
#define __DO(expr) \
({ typeof(expr) __ret; __ret = (expr); __ret; })
#define __DO_VOID(expr) \
(void) (expr)
Run Code Online (Sandbox Code Playgroud)
现在我们可以在两个实现之间静态切换,具体取决于表达式的实际类型.但事实上,天真的解决方案不起作用,见下文.
#define DO(expr) \
__builtin_choose_expr(__type_is_void(expr), \
__DO_VOID(expr), \
__DO(expr)) # won't work
Run Code Online (Sandbox Code Playgroud)
尝试编译此代码传递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
Run Code Online (Sandbox Code Playgroud)
虽然__DO_VOID选择了,但会__DO产生错误.手动中描述了此行为:
...未使用的表达式(
exp1或exp2取决于值const_exp)仍可能生成语法错误.这可能会在将来的修订中发生变化.
诀窍是用原始的void expr替换一些非void值来编译__DO案例(当expr无效时无论如何都是死代码).
#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!
Run Code Online (Sandbox Code Playgroud)
而已!以下是Ideone的完整源代码:http://ideone.com/EFy4pE
| 归档时间: |
|
| 查看次数: |
1847 次 |
| 最近记录: |