Reputation: 1526
If I'm defining a generic macro, using __typeof__
/typeof
, is there any way to also pick a printf
conversion specifier, in a generic way ?
what I mean is, for e.g:
#define max(a,b) \
({ typeof (a) _a = (a); \
typeof (b) _b = (b); \
DEBUG(( "%" __PRI_TYPE_PREFIX(a) > "%" __PRI_TYPE_PREFIX(b) "?", _a, _b)) \ <-- hypothetical
_a > _b ? _a : _b; })
is possible ?
Upvotes: 3
Views: 1428
Reputation: 145839
Using C11 _Generic
, for example (must be completed for complete check):
#define DEBUG_INT(a, b) DEBUG("%d %d?", (a), (b))
#define DEBUG_DOUBLE(a, b) DEBUG("%f %f?", (a), (b))
#define FAIL(a, b) assert(0)
#define max(a,b) \
({ typeof (a) _a = (a); \
typeof (b) _b = (b); \
_Generic((_a), int: DEBUG_INT, double: DEBUG_DOUBLE, default: FAIL))(_a, _b); \
_a > _b ? _a : _b; })
or using __builtin_types_compatible_p
gcc extension:
#define max(a,b) \
({ typeof (a) _a = (a); \
typeof (b) _b = (b); \
if (__builtin_types_compatible_p(typeof(int), _a) && __builtin_types_compatible_p(typeof(int), _a)) DEBUG_INT(_a, _b); \
else if (__builtin_types_compatible_p(typeof(double), _a) && __builtin_types_compatible_p(typeof(double), _a)) DEBUG_DOUBLE(_a, _b); \
else FAIL(_a, _b);
_a > _b ? _a : _b; })
Upvotes: 2
Reputation: 249223
#include <stdio.h>
#define FMT(_pre_, x, _post_) _Generic((x), \
char: _pre_ "%c" _post_, \
int: _pre_ "%d" _post_, \
long: _pre_ "%ld" _post_)
int main()
{
int x = 42;
long y = 432144312432321;
printf(FMT("foo: ", x, "\n"), x);
printf(FMT("bar: ", y, "\n"), y);
return 0;
}
The pre and post stuff is a little ugly, but I didn't find a better way yet. We cannot rely on string concatenation in the C preprocessor, because _Generic
is evaluated by the compiler, too late.
Upvotes: 2
Reputation: 212979
You can use C11's _Generic
capability to do this, e.g.
#define printf_dec_format(x) _Generic((x), \
char: "%c", \
signed char: "%hhd", \
unsigned char: "%hhu", \
signed short: "%hd", \
unsigned short: "%hu", \
signed int: "%d", \
unsigned int: "%u", \
long int: "%ld", \
unsigned long int: "%lu", \
long long int: "%lld", \
unsigned long long int: "%llu", \
float: "%f", \
double: "%f", \
long double: "%Lf", \
char *: "%s", \
void *: "%p")
#define print(x) printf(printf_dec_format(x), x)
(example taken from: Rob's Programming Blog)
Upvotes: 3