Let's assume I have a macro (more details about why, is below in the P.S. section)
void my_macro_impl(uint32_t arg0, uint32_t arg1, uint32_t arg2);
...
#define MY_MACRO(arg0, arg1, arg2) my_macro_impl((uint32_t)(arg0), (uint32_t)(arg1), (uint32_t)(arg2))
The HW on which this macro is going to be used is little endian and uses 32bit architecture so that all the pointers are up to (and including) 32 bit width. My goal is to warn the user when it passes uint64_t or int64_t parameter by mistake.
I was thinking about using sizeof like this
#define MY_MACRO(arg0, arg1, arg2) do \
{ \
static_assert(sizeof(arg0) <= sizeof(uint32_t)); \
static_assert(sizeof(arg1) <= sizeof(uint32_t)); \
static_assert(sizeof(arg2) <= sizeof(uint32_t)); \
my_macro_impl((uint32_t)(arg0), (uint32_t)(arg1), (uint32_t)(arg2)); \
} while (0)
But the user can use MY_MACRO with a bit-field and then my code fails to compile:
error: invalid application of 'sizeof' to bit-field
Question: Is there an option to detect at the compilation time if the size of the macro argument larger than, let's say, uint32_t?
P.S.
The MY_MACRO is going to act similarly to printf in a real-time embedded environment. This environment has a HW logger which may receive up to 5 parameters, each parameter should be 32 bits. The goal is to preserve the standard format as for printf. The format strings are parsed offline and the parser is well aware that every parameter is 32 bits, so it will cast it based on the %... from the format string. Possible usages are below.
Not desired usage:
uint64_t time = systime_get();
MY_MACRO_2("Starting execution at systime %llx", time); // WRONG! only the low 32 bits are printed. I want to detect it and fail the compilation.
Expected usage:
uint64_t time = systime_get();
MY_MACRO_3("Starting execution at systime %x%x", (uint32_t)(time >> 32), (uint32_t)time); // OK!
The following approach may work for this need:
#define CHECK_ARG(arg) _Generic((arg), \
int64_t : (arg), \
uint64_t : (arg), \
default : (uint32_t)(arg))
Then, the MY_MACRO can be defined as
#define MY_MACRO(a0, a1, a2) do \
{ \
uint32_t arg1 = CHECK_ARG(a0); \
uint32_t arg2 = CHECK_ARG(a1); \
uint32_t arg3 = CHECK_ARG(a2); \
my_macro_impl(arg1, arg2, arg3);\
} while (0)
In such case, when passing for example uint64_t, a warning is fired:
warning: implicit conversion loses integer precision: 'uint64_t' (aka
'unsigned long long') to 'uint32_t' (aka 'unsigned int')
[-Wshorten-64-to-32]
Note:
Other types like double, 128/256 bit types can be handled similarly.
Appropriate warnings should be enabled.
EDIT:
Inspired by Lundin's comment and answer, the proposed above solution can easily be modified to a portable version which will cause compilation error and not just a compiler warning.
#define CHECK_ARG(arg) _Generic((arg), \
int64_t : 0, \
uint64_t : 0, \
default : 1)
So the MY_MACRO can be modified to
#define MY_MACRO(a0, a1, a2) do \
{ \
_Static_assert(CHECK_ARG(a1) && \
CHECK_ARG(a2) && \
CHECK_ARG(a3), \
"64 bit parameters are not supported!"); \
my_macro_impl((uint32_t)(a1), (uint32_t)(a2), (uint32_t)(a3)); \
} while (0)
This time, when passing uint64_t parameter MY_MACRO(1ULL, 0, -1), the compilation fails with error:
error: static_assert failed due to requirement '_Generic((1ULL), long
long: 0, unsigned long long: 0, default: 1) && (_Generic((0), long
long: 0, unsigned long long: 0, default:
1) && _Generic((-1), long long: 0, unsigned long long: 0, default: 1))' "64 bit parameters are not supported!"
The type of the ternary ?: expression is the common type of its second and third arguments (with integer promotion of smaller types). So the following version of your MY_MACRO will work in a 32-bit architecture:
static_assert(sizeof(uint32_t) == sizeof 0, ""); // sanity check, for your machine
#define MY_MACRO(arg0, arg1, arg2) \
do { \
static_assert(sizeof(0 ? 0 : (arg0)) == sizeof 0, ""); \
static_assert(sizeof(0 ? 0 : (arg1)) == sizeof 0, ""); \
static_assert(sizeof(0 ? 0 : (arg2)) == sizeof 0, ""); \
my_macro_impl((uint32_t)(arg0), (uint32_t)(arg1), (uint32_t)(arg2)); \
} while (0)
Moreover, this solution should work with all versions of C and C++ (with, if necessary, a suitable definition of static_assert).
Note this macro, like the OP's original, has function semantics in that the arguments are evaluated only once, unlike for example the notorious MAX macro.
Question: Is there an option to detect at the compilation time if the size of the macro argument larger than, let's say, uint32_t?
The only way to do this portably, is by generating a compiler error with _Generic. If you want the error to be pretty and readable, you feed the result of _Generic to _Static_assert, so that you can type out a custom string as compiler message.
Your specification seems to be this:
Everything must be compile-time checks.
The macro can get 1 to 5 parameters of any type.
Only int32_t and uint32_t are allowed types.
This means that you have to write a variadic macro and it must accept 1 to 5 parameters.
Such a macro can be written like this:
#define COUNT_ARGS(...) ( sizeof((uint32_t[]){__VA_ARGS__}) / sizeof(uint32_t) )
#define MY_MACRO(...) \
_Static_assert(COUNT_ARGS(__VA_ARGS__)>0 && COUNT_ARGS(__VA_ARGS__)<=5, \
"MY_MACRO: Wrong number of arguments");
COUNT_ARGS creates a temporary compound literal of as many objects as you give the macro. If they are wildly incompatible with uint32_t you might get compiler errors/warnings here already. If not, COUNT_ARGS will return the number of arguments passed.
With that out of the way, we can do the actual, portable type check of each item in the variable argument list. To check the type of one single item with _Generic:
#define CHECK(arg) _Generic((arg), uint32_t: 1, int32_t: 1, default: 0)
Then pass the result of that on to _Static_assert. However, for 5 arguments we would need to check 1 to 5 items. We can "chain" a number of macros for this purpose:
#define CHECK(arg) _Generic((arg), uint32_t: 1, int32_t: 1, default: 0)
#define CHECK_ARGS1(arg1,...) CHECK(arg1)
#define CHECK_ARGS2(arg2,...) (CHECK(arg2) && CHECK_ARGS1(__VA_ARGS__,0))
#define CHECK_ARGS3(arg3,...) (CHECK(arg3) && CHECK_ARGS2(__VA_ARGS__,0))
#define CHECK_ARGS4(arg4,...) (CHECK(arg4) && CHECK_ARGS3(__VA_ARGS__,0))
#define CHECK_ARGS5(arg5,...) (CHECK(arg5) && CHECK_ARGS4(__VA_ARGS__,0))
Each macro checks the first argument passed to it, then forwards the rest of them, if any, to the next macro. The trailing 0 is there to shut up ISO C warnings about rest arguments required for variadic macros.
We can bake the calls to these into a _Static_assert that calls the proper macro in the "chain" corresponding to the number of arguments:
_Static_assert(COUNT_ARGS(__VA_ARGS__) == 1 ? CHECK_ARGS1(__VA_ARGS__,0) : \
COUNT_ARGS(__VA_ARGS__) == 2 ? CHECK_ARGS2(__VA_ARGS__,0) : \
COUNT_ARGS(__VA_ARGS__) == 3 ? CHECK_ARGS3(__VA_ARGS__,0) : \
COUNT_ARGS(__VA_ARGS__) == 4 ? CHECK_ARGS4(__VA_ARGS__,0) : \
COUNT_ARGS(__VA_ARGS__) == 5 ? CHECK_ARGS5(__VA_ARGS__,0) : 0, \
"MY_MACRO: incorrect type in parameter list " #__VA_ARGS__); \
Full code with examples of use:
#include <stdint.h>
#define COUNT_ARGS(...) ( sizeof((uint32_t[]){__VA_ARGS__}) / sizeof(uint32_t) )
#define CHECK(arg) _Generic((arg), uint32_t: 1, int32_t: 1, default: 0)
#define CHECK_ARGS1(arg1,...) CHECK(arg1)
#define CHECK_ARGS2(arg2,...) (CHECK(arg2) && CHECK_ARGS1(__VA_ARGS__,0))
#define CHECK_ARGS3(arg3,...) (CHECK(arg3) && CHECK_ARGS2(__VA_ARGS__,0))
#define CHECK_ARGS4(arg4,...) (CHECK(arg4) && CHECK_ARGS3(__VA_ARGS__,0))
#define CHECK_ARGS5(arg5,...) (CHECK(arg5) && CHECK_ARGS4(__VA_ARGS__,0))
#define MY_MACRO(...) \
do { \
_Static_assert(COUNT_ARGS(__VA_ARGS__)>0 && COUNT_ARGS(__VA_ARGS__)<=5, \
"MY_MACRO: Wrong number of arguments"); \
_Static_assert(COUNT_ARGS(__VA_ARGS__) == 1 ? CHECK_ARGS1(__VA_ARGS__,0) : \
COUNT_ARGS(__VA_ARGS__) == 2 ? CHECK_ARGS2(__VA_ARGS__,0) : \
COUNT_ARGS(__VA_ARGS__) == 3 ? CHECK_ARGS3(__VA_ARGS__,0) : \
COUNT_ARGS(__VA_ARGS__) == 4 ? CHECK_ARGS4(__VA_ARGS__,0) : \
COUNT_ARGS(__VA_ARGS__) == 5 ? CHECK_ARGS5(__VA_ARGS__,0) : 0, \
"MY_MACRO: incorrect type in parameter list " #__VA_ARGS__); \
} while(0)
int main (void)
{
//MY_MACRO(); // won't compile, "empty initializer braces"
//MY_MACRO(1,2,3,4,5,6); // static assert "MY_MACRO: Wrong number of arguments"
MY_MACRO(1); // OK, all parameters int32_t or uint32_t
MY_MACRO(1,2,3,4,5); // OK, -"-
MY_MACRO(1,(uint32_t)2,3,4,5); // OK, -"-
//MY_MACRO(1,(uint64_t)2,3,4,5); // static assert "MY_MACRO: incorrect type..."
//MY_MACRO(1,(uint8_t)2,3,4,5); // static assert "MY_MACRO: incorrect type..."
}
This should be 100% portable and doesn't rely on the compiler giving extra diagnostics beyond what's required by the standard.
The old do-while(0) trick is there to allow compatibility with icky-style brace formatting standards such as if(x) MY_MACRO(1) else. See Why use apparently meaningless do-while and if-else statements in macros?
Related
I'm trying to build a simple SIGNOF macro:
#define SIGNOF(a) ((a) < 0 ? -1 : 1)
If a is negative it should return -1, otherwise 1. If a is an unsigned type, it should always return 1 and the compiler can optimize away the negative code path.
However, GCC rightfully warns me that
error: comparison of unsigned expression in ‘< 0’ is always false [-Werror=type-limits]
29 | #define SIGNOF(a) ((a) < 0 ? -1 : 1)
But in this case I actually want this behavior. Is there any way to tell the compiler that this is intentional, similar to /* fall-though */ in a switch-case?
If your compiler supports it, you can use _Generic:
#define SIGNOF(a) _Generic(a, unsigned char: 1, \
unsigned short: 1, \
unsigned int: 1, \
unsigned long: 1, \
unsigned long long: 1, \
default: (a) < 0 ? -1 : 1)
What works is
static inline int __signof(long long a)
{
return a < 0 ? -1 : 1;
}
#define SIGNOF(a) _Generic(a, unsigned char: 1, \
unsigned short: 1, \
unsigned int: 1, \
unsigned long: 1, \
unsigned long long: 1, \
default: __signof(a))
This seems to fix the warning problem, at the expense of evaluating the operand twice:
#define SIGNOF(a) ((a) == 0 ? +1 : ((a) > 0) ? +1 : -1)
I observe that since the proposed DIV_ROUND() macro evaluates both its arguments twice, it also has problems if the arguments have side effects (increments, function calls, etc).
Time for a hideous workaround:
#define SIGNOF_(a) ((a) < 0 ? -1 : 1)
#ifdef __GNUC__
#define SIGNOF(a) ({ \
typeof(a) _a = (a); \
_Pragma("GCC diagnostic push") \
_Pragma("GCC diagnostic ignored \"-Wtype-limits\"") \
int _r = SIGNOF_(_a); \
_Pragma("GCC diagnostic pop") \
_r; })
#else
#define SIGNOF(a) SIGNOF_(a)
#endif
It makes use of GNU C "statement expressions" (({ statements; })) and the typeof operator. The initialization _a = (a); is to catch any -Wtype-limit warnings in the macro parameter a before the warning is temporarily disabled by the pragmas.
During the developing of static library I met the necessity to test the library functions.
The functions checks are not the problem. The main problem is to test every macro definition that the library provides.
I've started with the code like
/* For non-vital macro (OS/WORDSIZE detections) */
# if defined(BXI_ARCH_X32)
printf(" defined : BXI_ARCH_X32\n");
# endif
# if defined(BXI_ARCH_X64)
printf(" defined : BXI_ARCH_X64\n");
# endif
<...>
/* For vital macro */
#if defined(BXI_OS)
printf(" defined : BXI_OS : \"%s\"\n", BXI_OS);
#else
print_failed();
#endif
#if defined(BXI_BITS)
printf(" defined : BXI_BITS: %d\n", BXI_BITS);
#else
print_failed();
#endif
#if defined(BXI_ARCH)
printf(" defined : BXI_ARCH: \"%s\"\n", BXI_ARCH);
#else
print_failed();
#endif
That was cool, but very time-consuming. I wanted a tool that will generate the code for me, or some trick that will allow me to autogenerate the tests via macro like this
TEST_MACRO(BXI_OS)
But, as you know, macro definitions can't generate #if/#else/#endif directives.
I needed a solution that will not only check if the macro defined at runtime, but also print its value to output.
I've met a simillar problem and found another nice trick to implement your TEST_BXI_MACRO_EXISTS with no string.h and extra function calls:
#define STRINGIZE_I(x) #x
#define TEST_BXI_MACRO_EXISTS(name) (#name [0] != STRINGIZE_I(name) [0])
This trick uses the same assumption that stringized value of defined macro does not match stringized name of that macro. But for my case I only needed to check if macro is defined as a numeric constant, string literal or empty value. No function-like macros and other stuff.
This is how it works:
#define MACRO "Content"
TEST_BXI_MACRO_EXISTS(MACRO)
// translates to ("MACRO"[0] != "\"Content\""[0])
// first letter of a valid macro name can never be equal to '"'
#define MACRO 3.14
TEST_BXI_MACRO_EXISTS(MACRO)
// translates to ("MACRO"[0] != "3.14"[0])
// first letter of a valid macro name can never be equal to a digit
#define MACRO
TEST_BXI_MACRO_EXISTS(MACRO)
// translates to ("MACRO"[0] != ""[0])
// first letter of a valid macro name can never be equal to a '\0'
This approach can also be easily used to test whether macro defines a numeric constant, string literal or empty value like your approach does by checking the value of STRINGIZE_I(name) [0].
So far I have no idea how to test function-like macros this way, but I thought sharing this with others could be useful anyway.
But, as this is Q&A-style article, I've found the solution.
The final result looks as follows:
TEST_BXI_MACRO_STRING(BXI_OS);
TEST_BXI_MACRO_STRING(BXI_ARCH);
TEST_BXI_MACRO_I32 (BXI_BITS);
TEST_BXI_MACRO_EXISTS_WEAK(BXI_ARCH_X32); // _WEAK as we don't need to fail
TEST_BXI_MACRO_EXISTS_WEAK(BXI_ARCH_X64);
The result:
Let us see every one of them closely
TEST_BXI_MACRO_STRING
This one is pretty simple:
#define TEST_BXI_MACRO_STRING(name) \
do \
{ \
print_macro_name(#name); \
if (!TEST_BXI_MACRO_DEFINED(#name, name(1))) \
print_macro_undefined_exit(); \
if (strlen(name "") == 0) \
print_macro_undefined_exit(); \
print_macro_value_string(name ""); \
} \
while (0)
We just using the idea that C allows const strings auto-concatenation. So when the macro exists we will receive
#define MACRO "Content"
"Content" "" = "Content"
and when it doesn't
"" = ""
Then we look at the length of the resulting string, and when it's 0 - bingo, macro is not defined. This will NOT work for "" macro, but this special case could be checked with TEST_BXI_MACRO_EXISTS
TEST_BXI_MACRO_I32
#define TEST_BXI_MACRO_I32(name) \
do \
{ \
print_macro_name(#name); \
if (!TEST_BXI_MACRO_DEFINED(#name, name(1))) \
print_macro_undefined_exit(); \
if ((5 * name + 1) == 5) \
print_macro_undefined_exit(); \
print_macro_value_signed(name + 0); \
} \
while (0)
NOTE: you can similarly create ...MACRO_U32 version just by replacing the printer formatter.
Here we use the fact that '+' operator could be unary AND binary.
Let us simulate three cases:
#define MACRO (10)
In this case the complete formula will look as follows:
5 * 10 + 1 => 50 + 1 => 51
#define MACRO (0)
In this case the multiplication fades out:
5 * 0 + 1 => 0 + 1 => 1
In some cases you can use this for additional check if the defined macro is 0 (like for preprocessing options and stuff)
#define MACRO
This case shows some math magic:
5 * + 1 => 5 * (+1) => 5 * 1 => 5
As +1 is interpreted as simple 1 we receive 5.
TEST_BXI_MACRO_EXISTS
#define TEST_BXI_MACRO_DEFINED_I(strstr, fnc) (strcmp(#fnc, strstr "(1)"))
#define TEST_BXI_MACRO_DEFINED(str, fnc) TEST_BXI_MACRO_DEFINED_I(str, fnc)
#define TEST_BXI_MACRO_EXISTS(name) \
do \
{ \
print_macro_name(#name); \
if (!TEST_BXI_MACRO_DEFINED(#name, name(1))) \
print_macro_undefined_exit(); \
else \
print_macro_defined(); \
} \
while (0)
This implementation uses the fact that the string value of macro should not expand same as its name (as #define A A is useles)
Additional functions
For those who want the printing functions, here they are:
void print_macro_name(const char * name)
{
printf(" checking: %-20s: ", name);
}
void print_macro_undefined_exit(void)
{
printf("\033[1;31mUNDEFINED\033[0m\n");
exit(1);
}
void print_macro_defined(void)
{
printf("\033[1;33mDEFINED\033[0m\n");
}
void print_macro_undefined(void)
{
printf("\033[1;32mUNDEFINED\033[0m\n");
}
void print_macro_value_string(const char * value)
{
printf("\"%s\"\n", value);
}
void print_macro_value_signed(i32 value)
{
printf("%d\n", value);
}
void print_macro_value_unsigned(u32 value)
{
printf("%u\n", value);
}
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__; \
})
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 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.
So here is how we can check for "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.
So __builtin_choose_expr intrinsic is something like a "static switch" evaluated at compile-time.
Preparation
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)
Naive solution
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 or exp2 depending on the value of const_exp) may still generate syntax errors. This may change in future revisions.
Working solution
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
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.
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;
}
If you really need to return from macro, use inline function instead.
To check that two variables have the same structure type I use a macro
#define assert_same_struct_types(a, b) ((void) (sizeof((a)=(b))))
If some function-like macro
#define m(a,b) blablabla
assumes a and b should be of the same structure type, I add a compile time check:
#define m(a,b) (assert_same_struct_types(a, b), blablabla)
which provokes compiler error if caller of m(a,b) accidentally passes to m different types of structs.
However, this approach doesn't always work for builtin and pointer types due to implicit conversions between them.
So, is it possible to solve this problem for arbitrary types, not necessarily structs?
I need a solution for C89, however, it would be interesting to hear about C99 or C11 possibilities.
#define ASSERT_SAME_TYPE(a, b) ((void) (&(a) == &(b)))
will get you a compile diagnostic and an error with -Werror (for gcc or a similar option for other compilers).
Note that a lot of compilers have a non standard extension typeof operator to get the type of an object and this can be used to check two types are the same.
This questions asks about a C89 solution, so far I didn't find a good way to do this, so instead of relying on C89, you can check if the compiler supports typeof and use it when available. Its not ideal but means as long as some developers use GCC/Clang/IntelC, the error gets caught. of course, if you tell your compiler only to support C89 this isn't going to help.
It gives better type checking but obviously fails to be of any use at all when not supported.
#ifdef __GNUC__
#define CHECK_TYPE(var, type) { \
typeof(var) *__tmp; \
__tmp = (type *)NULL; \
(void)__tmp; \
} (void)0
#define CHECK_TYPE_PAIR(var_a, var_b) { \
typeof(var_a) *__tmp; \
__tmp = (typeof(var_b) *)NULL; \
(void)__tmp; \
} (void)0
#define CHECK_TYPE_PAIR_INLINE(var_a, var_b) ((void)({ \
typeof(var_a) *__tmp; \
__tmp = (typeof(var_b) *)NULL; \
(void)__tmp; \
}))
#else
# define CHECK_TYPE(var, type)
# define CHECK_TYPE_PAIR(var_a, var_b)
# define CHECK_TYPE_PAIR_INLINE(var_a, var_b) (void)0
#endif
/* inline type checking - can mix in with other macros more easily using the comma operator,
* C11 gives best results here */
#if defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 201112L)
# define CHECK_TYPE_INLINE(val, type) \
(void)((void)(((type)0) != (0 ? (val) : ((type)0))), \
_Generic((val), type: 0, const type: 0))
#else
# define CHECK_TYPE_INLINE(val, type) \
((void)(((type)0) != (0 ? (val) : ((type)0))))
#endif
FUNC(param);
When param is char *,dispatch to func_string.
when it's int,dispatch to func_int
I think there may be a solution to this,as variable types are known at compile time..
This will be possible with C1X but not in the current standard.
It will look like this:
#define cbrt(X) _Generic((X), long double: cbrtl, \
default: cbrt, \
float: cbrtf)(X)
Variable types are known to the compiler, but not to the preprocessor (which sees the code simply as unstructured text a stream of tokens, and performs only simple replacement operations on it). So I am afraid you can't achieve this with C macros.
In C++, they invented templates to solve such problems (and more).
You can test for the characteristics of the types.
For example, int can hold a negative value, while char* can't. So if ((typeof(param))-1) < 0, param is unsigned:
if (((typeof(param))-1) < 0) {
do_something_with_int();
} else {
do_something_with_char_p();
}
The compiler obviously optimizes this out.
Try it here: http://ideone.com/et0v1
This would be even easier if the types had different sizes. For example, if you want to write a generic macro than can handle different character sizes:
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 has a __builtin_types_compatible_p() builtin function that can check for types compatibility:
if (__builtin_types_compatible_p(typeof(param), int)) {
func_int(param);
} else if (__builtin_types_compatible_p(typeof(param), char*)) {
func_string(param);
}
Try it here: http://ideone.com/lEmYE
You can put this in a macro to achieve what you are trying to do:
#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); \
} \
})
(The ({...}) is a GCC's statement expression, it allows a group of statements to be a rvalue.
The __builtin_choose_expr() builtin can choose the expression to compile. With __builtin_types_compatible_p this allows to trigger an error at compile-time if the type of param is not compatible with both int and char*: (by compiling somehting invalid in this case)
#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) \
) \
)
This is actually a slightly modified example from __builtin_choose_expr docs.
There is no possibility to run time check types in C89 / ANSI C, but there is an extension to gcc which allows it. typeof or something along those lines if I remember. I saw it in the Linux Kernel once.
In kernel.h:
#define min(x, y) ({ \
typeof(x) _min1 = (x); \
typeof(y) _min2 = (y); \
(void) (&_min1 == &_min2); \
_min1 < _min2 ? _min1 : _min2; })
Take a look at this article: GCC hacks in the Linux kernel
When I first saw this I actually asked a question here on SO about:
min macro in kernel.h
I'm not quite sure exactly how you would use it to solve your problem, but it's something worth taking a look at.
You can't do this with a macro. Macro's value are substituted at compile time and are not intepreted. They are just substitutions.
Variable types are indeed known at compile time, however macro expansion takes place before compilation. I suggest you implement 2 overloaded functions instead of a macro.
my definition of a generic:
a structured abstract type which can only be fully defined with an input of other concrete types
this sounds exactly like a macro to me
pardon the psudo c code, my c is rusty
#include <stdio.h>
// todo: ret=self needs vec3##generic_t##_copy(self, ret);
// not to mention we should probably be using __builtin_add_overflow
// __builtin_add_overflow might actually itself be a reasonably generics method example
// please bear with me
#define GENERIC_VEC3_ADD(generic_t) \
generic_t vec3##generic_t##_add(generic_t self, generic_t other) {\
generic_t ret = self;\
ret[0] += other [0];;\
ret[1] += other [1];\
ret[2] += other [2];\
return ret;\
}
#define GENERIC_VEC3_FREPR(generic_t, printf_ts) \
int vec3##generic_t##_frepr(generic_t self, FILE fd)\
rerurn fprintf(fd, "<vec3##generic_t (##printf_ts##, printf_ts##, printf_ts##)>", \
self[0], self[1], self[2]);\
}
// here is the generic typedef, with some methods
#define GENERIC_VEC3(genetic_t, printf_ts) \
typedef vec3##generic_t generic_t[3];\
GENERIC_VEC3_ADD(generic_t) \
GENERIC_VEC3_FREPR(generic_t, printf_ts)
// later we decide what types we want this genic for
GENERIC_VEC3(int, %ul)
// and use our generic
int main()
{
vec3int foo = { 1, 2, 3 };;
vec3int bar = { 1, 2, 3 };;
vec3int sum = vec3int_add(foo, bar);
vec3int_frepr(sum, stderr);
fprintf(stderr, "\n");
exit EXIT_SUCCESS;
}