检查函数调用不作为参数传递(C宏)

在我工作的一个项目中,我们有一些实用程序宏,多次引用他们的参数.

让我们使用一个简单的例子:

#define ABS(a)  ( (a) < 0 ? (-(a)) : (a) )

在这一个很大的代码库,而在我们检查代码的时候,我现在发现一个函数调用被传递给一个宏.
这不是一个错误,但这意味着函数调用是多次,我通常不想要的.

在这种情况下,我们可以至少替代fabsf,fabs,abs,float / double / int,但是我们假设并不总是有一个很好的内置替换,宏将保留一个宏.

例:

f = ABS(dot_v3v3(vel,sp));

/* expands into */
f = ( ( dot_v3v3(vel,sp) ) < 0 ? (-( dot_v3v3(vel,sp) )) : ( dot_v3v3(vel,sp) ) );

所以我的问题是:

可以检测到宏内的调用函数(作为警告或错误)?

局部解决方

这里有一些我已经检查过的东西…

比较指针

这将导致函数调用不编译,但是具有像’1’这样的常量也给出错误以及像(b-c)这样的表达式的缺点.

#define ABS(a)  ((void)((&a) == (&a)),( (a) < 0 ? (-(a)) : (a) ))

注意:我发现这已经非常方便地指出了一些坏的宏使用,但由于它具有假阳性,它不能被留下.

C11泛型

使用_Generic,您可以将C宏转换为内联函数的包装器.这意味着在宏中调用多次函数调用的问题消失了.

#define ABS(a) \
    _Generic((a),\
        long double: my_abs_double(a),\
        float: my_abs_float(a),\
        int:  my_abs_int(a) \
        /* ... and so on,char,long,short... etc */ \
        )

这不是一个可行的解决方案 – 我们仍然支持不支持泛型的编译器.

解决方法

我在 MirOS C Preprocessor manual in the section on duplicating side effects中找到了这个技巧:
#define min(X,Y)                \
 ({ typeof (X) x_ = (X);          \
    typeof (Y) y_ = (Y);          \
    (x_ < y_) ? x_ : y_; })

相关文章

本程序的编译和运行环境如下(如果有运行方面的问题欢迎在评...
水了一学期的院选修,万万没想到期末考试还有比较硬核的编程...
补充一下,先前文章末尾给出的下载链接的完整代码含有部分C&...
思路如标题所说采用模N取余法,难点是这个除法过程如何实现。...
本篇博客有更新!!!更新后效果图如下: 文章末尾的完整代码...
刚开始学习模块化程序设计时,估计大家都被形参和实参搞迷糊...