我想用#define 制作一个简单的宏来返回两个数字中较小的一个。
我怎么能在 C 中做到这一点?提出一些想法,看看你是否也可以让它变得更加模糊。
我想用#define 制作一个简单的宏来返回两个数字中较小的一个。
我怎么能在 C 中做到这一点?提出一些想法,看看你是否也可以让它变得更加模糊。
通常:
#define min(a, b) (((a) < (b)) ? (a) : (b))
请注意,这会评估最小值两次,这是最近一个问题中灾难的原因。
但是你为什么要混淆它呢?
这个将结果存储在一个变量中,并且每个参数只计算一次。它基本上是一个穷人的内联函数+声明:
#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.
*/
而且,只是为了它,一个 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_; \
})
它没有被混淆,但我认为这适用于任何类型,在任何情况下,在(几乎,见评论)任何参数等;如果您能想到任何反例,请更正。
当然,您可以为此使用#define,但您为什么要这样做?使用#define 的问题,即使是带括号的,也是你使用这样的代码得到意想不到的结果(好吧,你实际上不会这样做,但它说明了问题)。
int result = min(a++, b++);
如果您使用的是 C++ 而不是 C,那么使用内联函数肯定会更好,它 (i) 避免多次评估参数,并且 (ii) 是类型安全的(您甚至可以提供采用其他类型值的版本,例如 unsigned ,双精度或字符串)。
inline int min(int a, int b) { return (a < b) ? a : b; }
我觉得这个方法很可爱:
#define min(a, b) (((a) + (b) - fabs((a) - (b))) * 0.5)
我想用#define 制作一个简单的宏来返回两个数字中较小的一个。
当数字是浮点数时,我想添加一个解决方案。
考虑当数字是浮点数并且其中一个数字不是非数字时。那么结果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
。它们都具有相同的价值。
如果我只是想稍微混淆一下,我可能会使用以下内容:
#define min(a,b) ((a) + ((b) < (a) ? (b) - (a) : 0))
我认为 Doynax 的解决方案也很可爱。通常对不止一次评估宏参数的保留。
对于稍微混淆,试试这个:
#define MIN(a,b) ((((a)-(b))&0x80000000) >> 31)? (a) : (b)
基本上,它减去它们,并将符号位视为 1 或 0。如果减法结果为负数,则第一个参数较小。