Ani
Ani

Reputation: 1526

__typeof variables and printf

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

Answers (3)

ouah
ouah

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

John Zwinck
John Zwinck

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

Paul R
Paul R

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

Related Questions