C语言中的MIN和MAX定义在哪里?

实现这些最好的方法是什么,尽可能的泛型和类型安全?(主流编译器的编译器扩展/内置优先。)


当前回答

避免使用非标准编译器扩展,在纯标准C语言中实现完全类型安全的宏(ISO 9899:2011)。

解决方案

#define GENERIC_MAX(x, y) ((x) > (y) ? (x) : (y))

#define ENSURE_int(i)   _Generic((i), int:   (i))
#define ENSURE_float(f) _Generic((f), float: (f))


#define MAX(type, x, y) \
  (type)GENERIC_MAX(ENSURE_##type(x), ENSURE_##type(y))

使用

MAX(int, 2, 3)

解释

宏MAX基于类型参数创建另一个宏。如果为给定类型实现了此控制宏,则用于检查两个参数的类型是否正确。如果不支持该类型,则会出现编译器错误。

如果x或y的类型不正确,则ENSURE_宏中将出现编译器错误。如果支持更多类型,可以添加更多这样的宏。我假设只有算术类型(整数,浮点数,指针等)将被使用,而不是结构体或数组等。

如果所有类型都正确,将调用GENERIC_MAX宏。每个宏参数周围都需要额外的括号,这是编写C宏时通常的标准预防措施。

然后是c语言中隐式类型提升的常见问题。?:操作符平衡了第2和第3个操作数。例如,GENERIC_MAX(my_char1, my_char2)的结果将是一个int型。为了防止宏执行这种潜在危险的类型提升,使用了最终类型转换为预期类型。

基本原理

我们希望宏的两个参数具有相同的类型。如果其中一个是不同类型的,则宏不再是类型安全的,因为像?:这样的操作符将产生隐式类型提升。正因为如此,我们还总是需要将最终结果转换回上面解释的预期类型。

只有一个参数的宏可以用更简单的方式编写。但是对于2个或更多的参数,就需要包含一个额外的类型参数。因为不幸的是,这样的事情是不可能的:

// this won't work
#define MAX(x, y)                                  \
  _Generic((x),                                    \
           int: GENERIC_MAX(x, ENSURE_int(y))      \
           float: GENERIC_MAX(x, ENSURE_float(y))  \
          )

问题是,如果上面的宏被调用为带有两个int的MAX(1,2),它仍然会尝试宏展开_Generic关联列表的所有可能场景。因此ENSURE_float宏也会被展开,尽管它与int无关。由于该宏有意只包含float类型,因此代码无法编译。

为了解决这个问题,我在预处理器阶段使用##操作符创建了宏名,这样就不会意外地展开宏。

例子

#include <stdio.h>

#define GENERIC_MAX(x, y) ((x) > (y) ? (x) : (y))

#define ENSURE_int(i)   _Generic((i), int:   (i))
#define ENSURE_float(f) _Generic((f), float: (f))


#define MAX(type, x, y) \
  (type)GENERIC_MAX(ENSURE_##type(x), ENSURE_##type(y))

int main (void)
{
  int    ia = 1,    ib = 2;
  float  fa = 3.0f, fb = 4.0f;
  double da = 5.0,  db = 6.0;

  printf("%d\n", MAX(int,   ia, ib)); // ok
  printf("%f\n", MAX(float, fa, fb)); // ok

//printf("%d\n", MAX(int,   ia, fa));  compiler error, one of the types is wrong
//printf("%f\n", MAX(float, fa, ib));  compiler error, one of the types is wrong
//printf("%f\n", MAX(double, fa, fb)); compiler error, the specified type is wrong
//printf("%f\n", MAX(float, da, db));  compiler error, one of the types is wrong

//printf("%d\n", MAX(unsigned int, ia, ib)); // wont get away with this either
//printf("%d\n", MAX(int32_t, ia, ib)); // wont get away with this either
  return 0;
}

其他回答

这是一个较晚的答案,由于最近的发展。由于OP接受了依赖于不可移植的GCC(和clang)扩展类型的答案-或“干净”ISO C的__typeof__ -在GCC -4.9有一个更好的解决方案。

#define max(x,y) ( \
    { __auto_type __x = (x); __auto_type __y = (y); \
      __x > __y ? __x : __y; })

这个扩展的明显好处是每个宏参数只展开一次,不像__typeof__解决方案。

__auto_type是c++ 11的auto. type的有限形式。它不能(或不应该?)在c++代码中使用,尽管在使用c++ 11时没有很好的理由不使用auto的高级类型推断功能。

也就是说,我假设当宏包含在extern“C”{…}范围;例如,来自C头文件。AFAIK,这个扩展没有找到它的方式信息叮当

最简单的方法是将它定义为.h文件中的一个全局函数,如果您的程序是包含大量文件的模块化程序,则可以随时调用它。如果不是,double MIN(a,b){return (a<b?a:b)}是最简单的方法。

如果你需要min/max来避免昂贵的分支,你不应该使用三元运算符,因为它会编译成一个跳转。下面的链接描述了实现最小/最大函数而不进行分支的有用方法。

http://graphics.stanford.edu/~seander/bithacks.html#IntegerMinOrMax

在c++中有std::min和std::max,但是在C标准库中没有等价的。你可以自己用宏来定义它们

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

但是,如果您编写MAX(++a, ++b)这样的代码,就会出现问题。

避免使用非标准编译器扩展,在纯标准C语言中实现完全类型安全的宏(ISO 9899:2011)。

解决方案

#define GENERIC_MAX(x, y) ((x) > (y) ? (x) : (y))

#define ENSURE_int(i)   _Generic((i), int:   (i))
#define ENSURE_float(f) _Generic((f), float: (f))


#define MAX(type, x, y) \
  (type)GENERIC_MAX(ENSURE_##type(x), ENSURE_##type(y))

使用

MAX(int, 2, 3)

解释

宏MAX基于类型参数创建另一个宏。如果为给定类型实现了此控制宏,则用于检查两个参数的类型是否正确。如果不支持该类型,则会出现编译器错误。

如果x或y的类型不正确,则ENSURE_宏中将出现编译器错误。如果支持更多类型,可以添加更多这样的宏。我假设只有算术类型(整数,浮点数,指针等)将被使用,而不是结构体或数组等。

如果所有类型都正确,将调用GENERIC_MAX宏。每个宏参数周围都需要额外的括号,这是编写C宏时通常的标准预防措施。

然后是c语言中隐式类型提升的常见问题。?:操作符平衡了第2和第3个操作数。例如,GENERIC_MAX(my_char1, my_char2)的结果将是一个int型。为了防止宏执行这种潜在危险的类型提升,使用了最终类型转换为预期类型。

基本原理

我们希望宏的两个参数具有相同的类型。如果其中一个是不同类型的,则宏不再是类型安全的,因为像?:这样的操作符将产生隐式类型提升。正因为如此,我们还总是需要将最终结果转换回上面解释的预期类型。

只有一个参数的宏可以用更简单的方式编写。但是对于2个或更多的参数,就需要包含一个额外的类型参数。因为不幸的是,这样的事情是不可能的:

// this won't work
#define MAX(x, y)                                  \
  _Generic((x),                                    \
           int: GENERIC_MAX(x, ENSURE_int(y))      \
           float: GENERIC_MAX(x, ENSURE_float(y))  \
          )

问题是,如果上面的宏被调用为带有两个int的MAX(1,2),它仍然会尝试宏展开_Generic关联列表的所有可能场景。因此ENSURE_float宏也会被展开,尽管它与int无关。由于该宏有意只包含float类型,因此代码无法编译。

为了解决这个问题,我在预处理器阶段使用##操作符创建了宏名,这样就不会意外地展开宏。

例子

#include <stdio.h>

#define GENERIC_MAX(x, y) ((x) > (y) ? (x) : (y))

#define ENSURE_int(i)   _Generic((i), int:   (i))
#define ENSURE_float(f) _Generic((f), float: (f))


#define MAX(type, x, y) \
  (type)GENERIC_MAX(ENSURE_##type(x), ENSURE_##type(y))

int main (void)
{
  int    ia = 1,    ib = 2;
  float  fa = 3.0f, fb = 4.0f;
  double da = 5.0,  db = 6.0;

  printf("%d\n", MAX(int,   ia, ib)); // ok
  printf("%f\n", MAX(float, fa, fb)); // ok

//printf("%d\n", MAX(int,   ia, fa));  compiler error, one of the types is wrong
//printf("%f\n", MAX(float, fa, ib));  compiler error, one of the types is wrong
//printf("%f\n", MAX(double, fa, fb)); compiler error, the specified type is wrong
//printf("%f\n", MAX(float, da, db));  compiler error, one of the types is wrong

//printf("%d\n", MAX(unsigned int, ia, ib)); // wont get away with this either
//printf("%d\n", MAX(int32_t, ia, ib)); // wont get away with this either
  return 0;
}