C语言 如何创建一个宏来检测类型并自动打印一个数字?

huus2vyu  于 2022-12-03  发布在  其他
关注(0)|答案(2)|浏览(281)

我有一个宏:

#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()。我最初的想法是用#iftypeof()检查我必须使用什么格式字符串。但这不起作用,因为我不能在宏扩展中使用#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*参数,并在运行时连接格式字符串。

zaq34kh6

zaq34kh61#

使用您当前的设计:
通过更改_assert()来解决问题,现在采用3个char* 参数,并在运行时连接格式字符串。
如果您打算使用printf,这正是您必须做的。
有办法解决吗?
当然!创建所有类型的所有可能组合,并在一个表达式中评估它们:

#define assert_equal(x, y) do {\
    typeof(x) evalx = x;\
    typeof(y) evaly = y;\
    _assert(evalx == evaly, __LINE__, __FILE__,\
        EVAL_TYPE_FORMATER(evalx, evaly), evalx, evaly\
    )\
} while (0)

#define EVAL_TYPE_FORMATER(a, b) \
   _Generic(+(a) \
   , int: _Generic(+(b) \
      , int: "%d != %d" \
      , long: "%d != %ld" \
      , double: "%d != %f" \
      ) \
   , long etc....

注意:使用+运算符,你可以在你的参数上应用整数提升,而不是处理charshort的某些情况。我喜欢把,放在前面,以便更好地缩进。
你可能对我的项目yio感兴趣,用它你可以只做_assert(evalx == evaly, __LINE__, __FILE__, evalx, " != ", evaly),但是它的作用和“传递3个参数”一样--对于每个参数,传递一个特殊的函数来打印参数的类型--evalx, " != ", evaly变成了6个参数。

wh6knrhe

wh6knrhe2#

问题是预处理器的语义不允许它知道C类型。预处理器只是一个宏处理器,它不知道C语言(只是识别C语言标记),而是扩展充满宏定义和宏扩展的文本文件。
当类型被分析(在编译器中)时,预处理器已经完成了编译单元的该部分,然后它不能基于编译器收集/生成的信息返回并以不同的方式扩展宏。
即使你考虑了C语言所能支持的所有可能的类型,预处理器也不知道C类型是什么,它在链中首先运行。

相关问题