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

时间:2013-12-18 15:17:31

标签: c clang

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

#define min(a, b) ((a) < (b) ? (a) : (b))

这使您可以进行双重评估 - 您执行min(f(), g())的情况,忘记fg有副作用,并且您必须花费数小时试图弄明白你的函数运行两次的原因。为了防止这种情况,您可以

#define min(a, b) ({__typeof__(a) _a = (a); \
    __typeof__(b) _b = (b); \
    _a < _b ? _a : _b;})

这在GCC下运行得很好,但是如果你通过-Wgnu设置的Clang运行它 - 这组警告属于-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;})

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

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

3 个答案:

答案 0 :(得分:13)

如果您真的是用C ++编写的,只需不要使用预处理器

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

(请注意,我已交换ba,因此如果两者相等,则会获得左侧操作数。)

否则no, not really

答案 1 :(得分: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)))

答案 2 :(得分:3)

Simple发布的C11解决方案看起来很理想,但是如果你没有C11编译器,你仍然可以定义一个具有内在类型安全性的宏(因为无论如何都是C类型的安全类型):

#define MIN(type, X, Y) min_ ## type(X, Y)

这个宏只允许传递已实现的类型,否则会出现编译错误。

示例:

#define MIN(type, X, Y) min_ ## type(X, Y)

long  min_long  (long x, long y);
char  min_char  (char x, char y);
float min_float (float x, float y);

int main()
{
  long  min_l = MIN (long, 5L, 10L);
  char  min_c = MIN (char, 'A', 'B');
  float min_f = MIN (float, 666.66f, 3.14f);

  printf("%ld\n", min_l);
  printf("%c\n", min_c);
  printf("%f\n", min_f);
}

char  min_char  (char x, char y)    { return x < y ? x : y; }
long  min_long  (long x, long y)    { return x < y ? x : y; }
float min_float (float x, float y)  { return x < y ? x : y; }

现在,如果您使用MIN(int, 1, 2)执行上述宏,则会出现编译器错误:“min_int,不存在此类函数”。