以下哪一个宏是安全的,为什么?

Chi*_*nna 5 c gcc c-preprocessor

为获得最多两个数字,我有以下宏

#define max(a,b) ((a) > (b) ? (a) : (b))

#define maxint(a,b) ({int _a = (a), _b = (b); _a > _b ? _a : _b; })
Run Code Online (Sandbox Code Playgroud)

以上两者之间有什么区别.哪一个更好用,为什么.我在这里找到了这些宏的信息.但无法理解它.

Bas*_*tch 7

第二个宏更安全,但使用GCC提供的非标准C扩展:语句表达式.但第一个表达是"通用的".使用typeof运算 GCC的扩展将帮助:

 #define mymax(a,b) ({typeof(a) _a = (a); typeof(b) _b = (b); \
                      _a > _b ? _a : _b; })
Run Code Online (Sandbox Code Playgroud)

为了对抗JaredPar回答中提出的问题,您可以使用预处理器连接和GCC特定__COUNTER__(或者只是更标准__LINE__),例如

 #define mymax_counted(a,b,c) ({typeof(a) _a##c = (a); \
                                typeof(b) _b##c = (b); \
                                _a##c > _b##c ? _a##c : _b##c; })
 #define mymax(a,b) mymax_counted(a,b,__COUNTER__)
Run Code Online (Sandbox Code Playgroud)

但即使这样也不完全是防止失败的(运气不好;可能会在某些调用中发生碰撞,就mymax(_a123,_b123)好像当时的唯一__COUNTER__碰巧是123).

实际上,使用内联函数更好(因为如果你调用mymaxfun(i++,t[i])行为定义得很好并给出相同的结果mymaxfun(t[i],i++),并且因为优化编译器会产生与使用宏时一样有效的代码):

static inline int mymaxfun(int a, int b) { return (a>b)?a:b; }
Run Code Online (Sandbox Code Playgroud)

遗憾的是,C没有泛型函数(考虑用它的模板切换到C++并使用std :: max); 但是C11使用关键字具有类型泛型表达式_Generic

宏是有用的(当掌握时),但是在调用宏时你应该非常小心参数中的副作用(例如mymax(i++,t[--i]++)),所以你总是应该关心并记录名称是宏还是别的东西(比如函数).根据经验,在函数调用表达式(函数调用和宏调用)中避免副作用 - 不可忽视++或者--还有许多其他副作用.

查看源代码的预处理器扩展形式; 所以对于一个foo.c源代码,运行gcc -C -E foo.c > foo.i(添加喜欢的任何预处理方案-I,-D等等相关)并观察内部foo.i,例如用less foo.i; 它总是很有启发性的.


Jar*_*Par 6

第二个宏更安全,因为它只对输入进行一次评估.如果输入是具有副作用的表达式,则这很重要

max(i++, --j); 
Run Code Online (Sandbox Code Playgroud)

请注意,我说更安全,不安全.这个宏仍然可能是不正确的,因为在范围内可能存在已经命名的本地_a_b.想象一下如果执行以下操作将会发生什么

int _a = 42;
int _b = 13;
maxint(_a, _b);
Run Code Online (Sandbox Code Playgroud)

它会扩展到

int _a = 42;
int _b = 13;
{int _a = (_a), _b = (_b); _a > _b ? _a : _b; })
Run Code Online (Sandbox Code Playgroud)