为获得最多两个数字,我有以下宏
#define max(a,b) ((a) > (b) ? (a) : (b))
#define maxint(a,b) ({int _a = (a), _b = (b); _a > _b ? _a : _b; })
以上两者之间有什么区别。哪一个更好用,为什么。 我找到了这些宏的信息here。但无法理解。
答案 0 :(得分:7)
第二个宏更安全,但使用GCC提供的非标准C扩展:statement expressions。但第一个表达是“通用的”。使用GCC的typeof扩展名会有所帮助:
#define mymax(a,b) ({typeof(a) _a = (a); typeof(b) _b = (b); \
_a > _b ? _a : _b; })
要解决JaredPar's answer中提出的问题,您可以使用预处理器concatenation和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__)
但即使这样也不完全是防止失败的(运气不好;如果当时唯一的mymax(_a123,_b123)
碰巧是123,可能会在__COUNTER__
之类的调用中发生碰撞。)
实际上,使用inline function会更好(因为如果你调用mymaxfun(i++,t[i])
,行为定义得很好并且给出与mymaxfun(t[i],i++)
相同的结果,并且因为优化编译器会使代码生效就像使用宏时一样):
static inline int mymaxfun(int a, int b) { return (a>b)?a:b; }
可悲的是,C没有通用功能(考虑使用C++切换到templates并使用std::max);但C11使用_Generic
关键字
宏很有用(当掌握时),但是在调用宏时你应该非常小心参数中的副作用(例如mymax(i++,t[--i]++)
)所以你总是应该关心并且文档如果一个名字是一个宏或其他东西(像一个函数)。根据经验,在函数调用表达式(函数调用和宏调用)中避免副作用 - 值得注意的是++
或--
,还有许多其他副作用。
查看源代码的预处理器扩展形式;因此,对于foo.c
源代码,运行gcc -C -E foo.c > foo.i
(添加-I
,-D
等所有预处理器选项都是相关的)并查看foo.i
内部,例如与less foo.i
;它总是很有启发性的。
答案 1 :(得分:6)
第二个宏更安全,因为它只对输入进行一次评估。如果输入是具有副作用的表达式(例如
),这一点很重要max(i++, --j);
请注意,我说更安全,不安全。此宏仍然可能不正确,因为范围中的本地可能已经命名为_a
和_
b。想象一下如果执行以下操作将会发生什么
int _a = 42;
int _b = 13;
maxint(_a, _b);
它会扩展到
int _a = 42;
int _b = 13;
{int _a = (_a), _b = (_b); _a > _b ? _a : _b; })
答案 2 :(得分:2)
两者都不安全。请避免使用依赖于非标准C扩展(例如表达式语句)的华丽max
宏实现,如果您必须将代码移植到其他平台,这将给您带来各种麻烦。我认为,max
宏在我看来是由于其潜在的副作用而导致C标准库中最糟糕的事情之一。过去,为了安全起见,我{#undef
编辑max
。
最好将第二个宏maxint
编码为函数,因为它具有宏的所有缺点(例如,无法轻松调试,实例化的变量与本地冲突)但没有任何好处(例如,泛化) )。
<强>替代强>:
我的最爱:使用三元内联:a > b ? a : b
,您可以放下括号,因为您确切知道发生了什么。通过获取有价值的副本,它也会比尝试安全的宏更快。
建立自己的功能。考虑为整数类型定义max
,为浮点定义fmax
。 abs
和fabs
已经有了先例。