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)
以上两者之间有什么区别.哪一个更好用,为什么.我在这里找到了这些宏的信息.但无法理解它.
第二个宏更安全,但使用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
; 它总是很有启发性的.
第二个宏更安全,因为它只对输入进行一次评估.如果输入是具有副作用的表达式,则这很重要
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)