这个MIN宏如何工作?

时间:2014-11-18 20:40:33

标签: c macros

如果这是一个愚蠢的问题,请原谅我。我似乎无法弄清楚以下MIN宏是如何工作的:

#define MIN(x, y)  (y) ^ ((x ^ y) & -(x < y))

4 个答案:

答案 0 :(得分:3)

宏是预处理器指令,意味着无论在何处使用,它都将被相关的代码片段替换。

如果您使用MIN宏进行修改,我或其他人应该能够帮助解释它。

示例:

#include<stdio.h>

#define PLUS +

int main() {
    printf("%d", (1 PLUS 3));
}

这应该只输出4

修改

让我们分解你的宏......

我们有,

(y) ^ ((x ^ y) & -(x < y))
  • 让我们采取最后一部分(x < y)。如果1小于xy则为1,则为-(x < y)。因此,0xffffffff如果x较小而0则为((x ^ y) & -(x < y))

  • 现在,((x ^ y) & 0xffffffff)变为(x ^ y),即((x ^ y) & 0),如果x小于y,则为0,即(y) ^ (x ^ y)其他

  • 因此,整个宏变为x,即(y) ^ 0,如果x较小且y,即MIN其他。这确实是所需的{{1}}功能。

答案 1 :(得分:2)

如果x小于y,则:

  • (x < y)是1。
  • -(x < y)为-1。
  • ((x ^ y) & -(x < y))((x ^ y) & -1)(x ^ y),因为(anything & -1) == anything,因为-1是全部&#39; 1&#39;位。
  • y ^ (x ^ y)x,因为XOR是可交换的,而且y可以取消。

如果y小于或等于x,则:

  • (x < y)为0。
  • -(x < y)为0。
  • ((x ^ y) & -(x < y))((x ^ y) & 0)0,因为(anything & 0) == 0,因为0都是&#39; 0&#39}位。
  • y ^ 0y

宏当前有一个严重的错误:它需要围绕外部表达式使用括​​号,否则当在其他表达式中使用时,它将遇到具有运算符优先级的混乱。例如,MIN(2, 3) * 4当前扩展为(3) ^ ((2 ^ 3) & -(2 < 3)) * 4,其评估为7而不是正确的8,因为乘法在最终XOR之前完成。为同一个原因在每个参数替换周围加上括号也是一个好主意:

#define MIN(x, y) ((y) ^ (((x) ^ (y)) & -((x) < (y))))

如果平台使用two's complement整数,宏仍然有效,并且它可能不比MIN的明显定义快得多:

#define MIN(x, y) ((x) < (y) ? (x) : (y))

答案 2 :(得分:0)

请注意,如果x < y,则-(x < y)的结果将仅为0。所以它等同于:

y ^ 0

哪个是y

  • <没有特殊含义,意味着小于

答案 3 :(得分:0)

除了评论中其他人发布的解释之外,当扩展宏时,如果对参数进行多次评估,您还应该注意宏中的副作用。

对于MIN(x,y)的通常C风格定义(例如@Boann指出),请注意x, y都是两次。您的原始定义会将x扩展两次,y扩展三次。在没有进入序列点和短路评估的情况下,让我们说结果可能是不可预测的,至少可以说(甚至可能根据编译器而变化)。这是许多C ++程序员认为预处理器宏是邪恶的原因之一。

要查看此操作,请使用MIN(x++, y++)尝试这两个定义。对于一个更加邪恶的可能性,考虑一下

result = MIN( x, ShouldOnlyBeCalledOnce_BecauseThisFunctionHasSideEffects(y));

虽然预处理器仍然确实有它的位置(并且你可以用它做任何其他方式无法完成的事情),特别是使用C ++通常是一个好主意,以确定是否存在非预处理器解决方案本身。
例如:在重载时,C ++实现最初给了我们像

这样的东西
int min(int x, int y) { return (x < y) ? x : y); }
some_other_type min(some_other_type x, some_other_type y) { return (x < y) ? x : y; }

模板给了我们更多,如:

template <class T> const T& min (const T& a, const T& b) {
  return !(b < a) ? a : b;
}

宏的便利性,但没有多次扩展参数时可能出现的副作用。顺便说一句,如果你想知道为什么测试是!( b < a) ? a : b;而不是(a < b) ? a : b;,那是因为如果(a == b)a应该返回,并且因为-than是唯一需要为给定类型定义的关系,以支持各种容器(除其他外)。