c - 如何在编译时检查 `typeof` 的 void 值?

标签 c types void c-preprocessor compile-time

假设我想要一个适用于任何类型的 C 宏。 我正在使用 GCC 编译器 (>= 4.6) 并且可以使用 GNU99 宏。

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

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...

因此 TIMER 必须返回给定函数的值并打印其运行持续时间。 具有 void 返回类型的函数存在问题。

我显然可以有两个宏,如 TIMER_TYPE 和 TIMER_VOID,但我想使用单个 one to time 函数和任何返回值。

感谢您的建议。


这个 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__;                                          \
})

最佳答案

多么有趣的问题,荣誉!

经过几次实验,我找到了一个使用 __builtin_types_compatible_p and __builtin_choose_expr 的解决方案GCC 的内在特性。

__builtin_types_compatible_p

引用 GCC 手册:

Built-in Function: int __builtin_types_compatible_p (type1, type2)

You can use the built-in function __builtin_types_compatible_p to determine whether two types are the same.

This built-in function returns 1 if the unqualified versions of the types type1 and type2 (which are types, not expressions) are compatible, 0 otherwise. The result of this built-in function can be used in integer constant expressions.

This built-in function ignores top level qualifiers (e.g., const, volatile). For example, int is equivalent to const int.

下面是我们如何检查“voidness”的方法。

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

__builtin_choose_expr

Built-in Function: type __builtin_choose_expr (const_exp, exp1, exp2)

You can use the built-in function __builtin_choose_expr to evaluate code depending on the value of a constant expression. This built-in function returns exp1 if const_exp, which is an integer constant expression, is nonzero. Otherwise it returns exp2.

This built-in function is analogous to the ? : operator in C, except that the expression returned has its type unaltered by promotion rules. Also, the built-in function does not evaluate the expression that is not chosen. For example, if const_exp evaluates to true, exp2 is not evaluated even if it has side-effects.

If exp1 is returned, the return type is the same as exp1's type. Similarly, if exp2 is returned, its return type is the same as exp2.

所以 __builtin_choose_expr intrinsic 类似于在编译时评估的“静态开关”。

准备

我没有在此处粘贴您的 TIMER 宏,但我认为它能够将其拆分为两个版本:一个用于 void expr ,另一个用于其余版本。这里只是计算表达式并产生相同类型结果的 stub 。

#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 会产生错误。手册中描述了此行为:

... the unused expression (exp1 or exp2 depending on the value of const_exp) may still generate syntax errors. This may change in future revisions.

工作解决方案

技巧是用一些非 void 值替换原始的 void expr 以便能够编译 __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!

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

关于c - 如何在编译时检查 `typeof` 的 void 值?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/12453165/

相关文章:

c - 用 void * 初始化 C 中的数组

C 代码中的 Java 数组

Java队列链表

MySQL 截断 GROUP_CONCAT 函数的连接结果

java.lang.Void vs void vs Null

c++ - `static_cast<volatile void>` 对优化器意味着什么?

c - 关于带有 scanf 函数的数组的问题

c - 使用堆栈检查给定的字符串序列是否是回文

powershell - PowerShell 中的强类型引用?

转换到 _Bool