let's say that I want to have C macro that works on any type. I'm using GCC compiler (>= 4.6) and can use GNU99 macros.
//code...
any_type_t *retVal = function_that_runs_very_long_time(a, b, &&c, **d, &e, *f);
//other code...
usage of macro for TIMER can look for example like this
//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...
So TIMER has to return value of given function and print duration of its run.
There is problem with functions that have void
return type.
I can obviously have two macros like TIMER_TYPE and TIMER_VOID, but I want to use single one to time function with any return value.
Thank you for suggestions.
Edited example of this TIMER macro
#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__; \
})
As long as you've got typeof
and _Generic
, you can do also do it without __builtin_types_compatible_p
or __builtin_choose_expr
.
The caveat is that _Generic
won't let you match void
so instead of matching Expr
against void
, match (typeof(Expr)*){0}
against void*
.
Below is eldar-abusalimov example modified to use _Generic
instead of __builtin_types_compatible_p
and __builtin_choose_expr
:
#include <stdio.h>
#define __type_is_void(expr) _Generic((typeof(expr)*){0}, void*:1, default:0)
#define __expr_or_zero(expr) _Generic((typeof(expr)*){0}, void*:0, default:(expr))
#define DO(expr) \
_Generic((typeof(expr)*){0}, \
void*:__DO_VOID(expr), \
default:__DO(__expr_or_zero(expr)))
#define __DO(expr) \
({ typeof(expr) __ret; puts("do nonvoid"); __ret = (expr); __ret; })
#define __DO_VOID(expr) \
(void)({ puts("do void"); (void)(expr); })
void foo(void) { }
int bar(void) { return 1; }
int main(void)
{
DO(foo());
DO(bar());
return 0;
}
can you accept an answer of "this isn't really possible" ?
not the part about returning from a macro. but the part about conditionally testing expr for its return type.
in effect, you're asking for something like the following:
let's say instead of some magical check called "is_expr_type_void(expr)", you instead simply pass a 1 or a 0 at the time of the call to indicate is_void or !is_void in the following variation of your macro:
#define TIMER(is_void, expr, fmt_msg, ...) \
({ \
struct timeval before, after; \
uint64_t time_span; \
int time_span_sec, time_span_usec; \
gettimeofday(&before, NULL); \
if (is_void) \
(expr) \
else \
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, ...); \
if (!is_void) \
_timer_expr__; \
})
this simply cannot work. the preprocessor would create code for that if-else conditional in all cases, both void and non-void function calls. and both sides would compile fine for non-void functions. but the compiler would always choke on the "else" part of the conditional when TIMER is invoked with a void function … despite the fact that the code would never be called.
(now if there existed a really smart compiler that could both identify that it would be dead code and dead-strip it prior to flagging it as a compile time error, you'd be in luck! but i don't think gcc 4.6 is that smart … )
this leaves you with what would be a preferred option of a #if (is_void) conditional inside the #define. but that's simply not allowed. since, as this answer points out in attempting to answer a similar question about conditional preprocessing, the preprocessor is not turing-complete.
so … despite your desire to have a single macro, i think your simplest answer is to create one for void functions, and one for functions with return values.
What an interesting question, kudos!
After few experiments, I found a solution which uses __builtin_types_compatible_p
and __builtin_choose_expr
intrinsics of GCC.
__builtin_types_compatible_p
Quoting GCC manual:
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 typestype1
andtype2
(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 toconst int
.
So here is how we can check for "void
ness".
#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 returnsexp1
ifconst_exp
, which is an integer constant expression, is nonzero. Otherwise it returnsexp2
.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, ifconst_exp
evaluates to true,exp2
is not evaluated even if it has side-effects.If
exp1
is returned, the return type is the same asexp1
's type. Similarly, ifexp2
is returned, its return type is the same asexp2
.
So __builtin_choose_expr
intrinsic is something like a "static switch" evaluated at compile-time.
I don't paste here your TIMER
macro, but I assume it is able to split it into two versions: one for void expr
and one for the rest. Here are just stubs which evaluate the expression and yield the result of the same type.
#define __DO(expr) \
({ typeof(expr) __ret; __ret = (expr); __ret; })
#define __DO_VOID(expr) \
(void) (expr)
Now we can statically switch between two implementations, depending on the actual type of the expression. But in fact the naive solution doesn't work, see below.
#define DO(expr) \
__builtin_choose_expr(__type_is_void(expr), \
__DO_VOID(expr), \
__DO(expr)) # won't work
Attempt to compile this code passing a void expression gives the following error:
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
Although __DO_VOID
is chosen, __DO
generates errors. This behavior is described in manual:
... the unused expression (
exp1
orexp2
depending on the value ofconst_exp
) may still generate syntax errors. This may change in future revisions.
The trick is to substitute the original void expr
with some non-void value to be able to compile the __DO
case (which is anyway a dead code when expr
is 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!
That's it! Here is the complete source code on Ideone: http://ideone.com/EFy4pE
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With