如果我定义一个通用宏,使用__typeof__
/typeof
,是否有任何方法也可以选择printf
转换说明符,以通用的方式?
我的意思是,例如:
#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; })
您可以使用C11的_Generic
功能来完成此操作,例如
#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)
(示例取自:Rob的编程博客)
#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;
}
前和后的东西是有点丑,但我还没有找到一个更好的方法。我们不能在C预处理器中依赖字符串连接,因为_Generic
是由编译器求值的,太晚了。
例如,使用C11 _Generic
(必须完成完整检查):
#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; })
或使用__builtin_types_compatible_p
gcc扩展:
#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; })