在没有双重评估的情况下在Clang中实现min()和max()

bde*_*ham 9 c clang

min函数的经典预处理器版本看起来像

#define min(a, b) ((a) < (b) ? (a) : (b))
Run Code Online (Sandbox Code Playgroud)

这使你可以进行双重评估 - 你做的情况min(f(), g()),忘记fg有副作用,你必须花费数小时试图找出你的功能运行两次的原因.为了防止这种情况,你可以做到

#define min(a, b) ({__typeof__(a) _a = (a); \
    __typeof__(b) _b = (b); \
    _a < _b ? _a : _b;})
Run Code Online (Sandbox Code Playgroud)

这在GCC下运行得很好,但是如果你通过-Wgnu套装运行它- 这套警告属于-pedantic你的保护范围内- 你得到的错误就像

test.c:5:10: error: use of GNU statement expression extension [-Werror,-Wgnu]
        int a = min(3, 7);
                ^
test.c:1:22: note: expanded from macro 'min'
#  define min(a, b) ({__typeof__(a) _a = (a); __typeof__(b) _b = (b); _a < _b ? _a : _b;})
Run Code Online (Sandbox Code Playgroud)

是否有可能以防止双重评估的方式定义这些宏,并且 Clang可以接受哪些宏-pedantic?(是的,您可以禁用警告-Wno-gnu,在这种情况下,Clang处理语句表达没有问题.我问,因为我,因为我clang -pedantic太自负了.)

编辑:我在C工作.我也标记了这个C++,因为我认为解决方案可能适用于C++以及C.哎呀 - 忘了模板!抱歉模棱两可.

Lig*_*ica 13

如果你真的用C++编写,那么就不要使用预处理器:

template <typename T>
const T min(const T& a, const T& b)
{
   return (b < a) ? b : a;
}
Run Code Online (Sandbox Code Playgroud)

(请注意,我换ba,让你得到左手操作,如果两者相等).

否则不,不是真的.

  • @Lundin:因为`<`运算符没有选择两个操作数之一.它给你一个布尔值.向我们展示您的天才C解决方案. (5认同)

Sim*_*ple 6

我认为这可以作为C11解决方案.

inline
int min(int const x, int const y)
{
    return y < x ? y : x;
}

inline
unsigned minu(unsigned const x, unsigned const y)
{
    return y < x ? y : x;
}

inline
long minl(long const x, long const y)
{
    return y < x ? y : x;
}

inline
unsigned long minul(unsigned long const x, unsigned long const y)
{
    return y < x ? y : x;
}

inline
long long minll(long long const x, long long const y)
{
    return y < x ? y : x;
}

inline
unsigned long long minull(unsigned long long const x, unsigned long long const y)
{
    return y < x ? y : x;
}

inline
float minf(float const x, float const y)
{
    return y < x ? y : x;
}

inline
double mind(double const x, double const y)
{
    return y < x ? y : x;
}

inline
long double minld(long double const x, long double const y)
{
    return y < x ? y : x;
}

#define MIN(X, Y) (_Generic((X) + (Y),   \
    int:                min,             \
    unsigned:           minu,            \
    long:               minl,            \
    unsigned long:      minul,           \
    long long:          minll,           \
    unsigned long long: minull,          \
    float:              minf,            \
    double:             mind,            \
    long double:        minld)((X), (Y)))
Run Code Online (Sandbox Code Playgroud)

  • +1,但你的`_Generic`表达式太复杂了.`_Generic((X)+(Y),int:min,unsigned:minu,...)((X),(Y))`就足够了.你也忘记了浮点类型. (2认同)