【发布时间】:2011-01-28 08:38:15
【问题描述】:
我想用#define 制作一个简单的宏来返回两个数字中较小的一个。
我如何在 C 中做到这一点?提出一些想法,看看你是否也可以让它变得更加模糊。
【问题讨论】:
-
MIN and MAX in C的可能重复
标签: c c-preprocessor minimum
我想用#define 制作一个简单的宏来返回两个数字中较小的一个。
我如何在 C 中做到这一点?提出一些想法,看看你是否也可以让它变得更加模糊。
【问题讨论】:
标签: c c-preprocessor minimum
通常:
#define min(a, b) (((a) < (b)) ? (a) : (b))
请注意,这至少会评估两次,这是 recent question 中发生灾难的原因。
但是你为什么要混淆它呢?
这个将结果存储在一个变量中,并且每个参数只计算一次。它基本上是一个穷人的内联函数 + 声明:
#define min(t, x, a, b) \
t x; \
{ \
t _this_is_a_unique_name_dont_use_it_plz_0_ = a; \
t _this_is_a_unique_name_dont_use_it_plz_1_ = b; \
x = _this_is_a_unique_name_dont_use_it_plz_0_ < \
_this_is_a_unique_name_dont_use_it_plz_1_ ? \
_this_is_a_unique_name_dont_use_it_plz_0_ : \
_this_is_a_unique_name_dont_use_it_plz_1_ ; \
}
像这样使用它:
min(int, x, 3, 4)
/* x is an int, equal to 3
Just like doing:
int x = min(3, 4);
Without double evaluation.
*/
【讨论】:
typeof 扩展名 (gcc.gnu.org/onlinedocs/gcc/Typeof.html),可以避免将类型名称作为宏参数提及。
还有一个 GNU C 示例:
#define MAX(a,b) ({ \
typeof(a) _a_temp_; \
typeof(b) _b_temp_; \
_a_temp_ = (a); \
_b_temp_ = (b); \
_a_temp_ = _a_temp_ < _b_temp_ ? _b_temp_ : _a_temp_; \
})
它没有被混淆,但我认为这适用于任何类型、任何上下文、(几乎,参见 cmets)任何参数等;如果您能想到任何反例,请更正。
【讨论】:
a 或 b 碰巧自己是名为 _a_temp_ 和 _b_temp_ 的变量。
__LINE__,但似乎不值得努力;要是有一个__UNIQUE__ 宏就好了……
当然,您可以为此使用#define,但您为什么要这样做?使用#define 的问题,即使有括号,你也会得到意想不到的结果(好吧,你实际上不会这样做,但它说明了问题)。
int result = min(a++, b++);
如果您使用的是 C++ 而不是 C,肯定会更好地使用内联函数,它 (i) 避免多次评估参数,并且 (ii) 是类型安全的(您甚至可以提供采用其他类型值的版本,如无符号、双精度或字符串)。
inline int min(int a, int b) { return (a < b) ? a : b; }
【讨论】:
<algorithm> 中已有一个。
__inline,GNU C89 中的__inline__)。
我觉得这个方法比较可爱:
#define min(a, b) (((a) + (b) - fabs((a) - (b))) * 0.5)
【讨论】:
我想用#define 制作一个简单的宏来返回两个数字中较小的一个。
当数字是浮点数时,我想添加一个解决方案。
考虑数字是浮点数并且其中一个数字是not-a-number。那么a < b 的结果总是false 而不管其他数字的值。
// the result is `b` when either a or b is NaN
#define min(a, b) (((a) < (b)) ? (a) : (b))
可能希望结果如下所示,其中“NaN 参数被视为缺失数据”。 C11脚注#242
a NaN | b NaN | a < b | min
-------+---------+---------+---------------
No | No | No | b
No | No | Yes | a
No | Yes | . | a
Yes | No | . | b
Yes | Yes | . | either a or b
使用 C 语言中的宏执行此操作将简单地包装支持上表的 fmin() 函数。当然代码通常应该直接使用fmin()函数。
#include <math.h>
#define my_fmin(a, b) (fmin((a), (b))
注意fmin(0.0, -0.0) 可能返回0.0 或-0.0。它们都有相同的值。
【讨论】:
NaN的答案,让我想到了这个问题
如果我只是想稍微混淆一下,我可能会使用类似的东西:
#define min(a,b) ((a) + ((b) < (a) ? (b) - (a) : 0))
我认为 Doynax 的解决方案也很可爱。通常对宏参数被多次评估的保留意见。
【讨论】:
为了稍微混淆,试试这个:
#define MIN(a,b) ((((a)-(b))&0x80000000) >> 31)? (a) : (b)
基本上,它减去它们,并将符号位视为 1 或 0。 如果减法结果为负数,则第一个参数较小。
【讨论】: