为什么在C中'max'宏是这样定义的?

问题描述 投票:0回答:4
 #define max(a,b) \
   ({ typeof (a) _a = (a); \
       typeof (b) _b = (b); \
     _a > _b ? _a : _b; })

为什么不简单地

(a>b ? a : b)

c macros
4个回答
20
投票

因为否则

max(f(1), f(2))
会调用两个函数之一两次:

f(1) > f(2) ? f(1) : f(2)

而是通过“缓存”

_a
_b
中的两个值,您就拥有了

({
    sometype _a = (a);
    sometype _b = (b);

    _a > _b ? _a : _b;
})

(正如其他人明确指出的那样,自动增量/自动减量也存在同样的问题)

我认为 Visual Studio 不支持这种方式。这是一个复合语句。请阅读此处 msvc 是否有 gcc 的 ({ }) 类似功能

我将补充一点,此处给出的 gcc 手册中复合语句的定义 http://gcc.gnu.org/onlinedocs/gcc-2.95.3/gcc_4.html#SEC62 显示了与该代码非常相似的代码max 的问题:-)


10
投票

它解决了以下主要问题:

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

当您使用具有副作用的表达式来调用它时,超出了对值的简单评估,事情可能不会按照您的想法行事。考虑代码:

int x = max (a++, b--);
由于宏是简单的文本替换,因此会产生以下翻译:

int x = ((a++) > (b--) ? a++ : b--);
这几乎肯定不是

您想要的,因为它会增加 a 或减少

b
两次,具体取决于它们的相对值。
但是,请考虑一下如果我们改为使用以下效果:

#define max(a,b) ({ \ typeof (a) _a = (a); \ typeof (b) _b = (b); \ _a > _b ? _a : _b; \ })

在这种情况下,它使用临时变量,有效地转换为:

int x = ({ int _a = a++; int _b = b--; _a > _b ? _a : _b; })

这只会运行副作用
一次。

但是,说实话,您应该完全放弃该宏并使用

inline

函数,甚至是非内联函数,因为大多数时候,即使没有

该建议,编译器也可以完成不错的优化工作.
早期 C 中宏的两个用例是类似函数的宏(例如您问题中的宏)和定义相关用途的常量。

前者最好使用内联函数

(1)

处理,后者则使用枚举。如今,我将宏的使用限制为非常简单的定义。

(1)
请记住,

inline 是一个建议,而类似函数的宏保证是内联的。但是,我发现编译器通常可以更好地确定是否遵循该建议(而不是开发人员)。

    
确定最大值的另一种方法(至少对于正数)


3
投票

由于 a 和 b 仅访问一次,因此 MAX(a++,b++) 给出正确的结果。


如果使用表达式调用宏,可能会导致意外行为。假设这个:


1
投票
int c = max(i++, j++);

在这种情况下,简单版本的最大值增加两倍。

    

© www.soinside.com 2019 - 2024. All rights reserved.