我有一个宏:
#define assert_equal(x, y) do {\
typeof(x) evalx = x;\
typeof(y) evaly = y;\
_assert(evalx == evaly, __LINE__, __FILE__,\
EVAL_TYPE_FORMATER(evalx)" != "EVAL_TYPE_FORMATER(evaly), evalx, evaly\
)\
} while (0)
它应该测试x和y是否相等,如果不相等,则打印两个值。_assert()
函数如下所示:
void _assert(bool condition, size_t line, const char* file, char* format, ...);
我需要帮助来创建宏EVAL_TYPE_FORMATER()
。我最初的想法是用#if
和typeof()
检查我必须使用什么格式字符串。但这不起作用,因为我不能在宏扩展中使用#if
。
下面是我最初的想法:
#define EVAL_TYPE_FORMATER(exp)\
#if typeof(exp) == char ||\
typeof(exp) == short ||\
typeof(exp) == int\
"%d"\
#elif typeof(exp) == long\
"%ld"\
...
但是正如你所看到的,is有很多问题,我该怎么做才能解决这个问题呢?
编辑:
较新的方法是使用_Generic
(感谢@Someprogrammerdude)。
#define EVAL_TYPE_FORMATER(exp) (_Generic((exp), \
char: "%d", \
short: "%d", \
int: "%d", \
long: "%ld", \
...
))
但是_Generic
的结果不能用来和一个常量连接,EVAL_TYPE_FORMATER(evalx)" != "EVAL_TYPE_FORMATER(evaly)
现在编译失败了,有没有办法解决这个问题?
编辑2:
解决方法是将_assert()
更改为现在采用3个char*
参数,并在运行时连接格式字符串。
2条答案
按热度按时间zaq34kh61#
使用您当前的设计:
通过更改_assert()来解决问题,现在采用3个char* 参数,并在运行时连接格式字符串。
如果您打算使用printf,这正是您必须做的。
有办法解决吗?
当然!创建所有类型的所有可能组合,并在一个表达式中评估它们:
注意:使用
+
运算符,你可以在你的参数上应用整数提升,而不是处理char
short
的某些情况。我喜欢把,
放在前面,以便更好地缩进。你可能对我的项目yio感兴趣,用它你可以只做
_assert(evalx == evaly, __LINE__, __FILE__, evalx, " != ", evaly)
,但是它的作用和“传递3个参数”一样--对于每个参数,传递一个特殊的函数来打印参数的类型--evalx, " != ", evaly
变成了6个参数。wh6knrhe2#
问题是预处理器的语义不允许它知道C类型。预处理器只是一个宏处理器,它不知道C语言(只是识别C语言标记),而是扩展充满宏定义和宏扩展的文本文件。
当类型被分析(在编译器中)时,预处理器已经完成了编译单元的该部分,然后它不能基于编译器收集/生成的信息返回并以不同的方式扩展宏。
即使你考虑了C语言所能支持的所有可能的类型,预处理器也不知道C类型是什么,它在链中首先运行。