使用无符号整数的最大值时,“ - 1”是否正确?

时间:2017-12-07 15:30:45

标签: c++

是否有任何c ++标准段落表示使用-1这是可移植且正确的方法或正确执行此操作的唯一方法是使用预定义值?

我与我的同事进行了对话,更好的是:使用-1获取最大无符号整数或使用limits.hstd::numeric_limits中的值?

我已经告诉我的同事,使用limits.hstd::numeric_limits预定义的最大值是可行且干净的方式,但同事反对-1同样是便携式作为数字限制,以及更多,它还有一个优点:

unsigned short i = -1; // unsigned short max

可以轻松更改为任何其他类型,例如

unsigned long i = -1; // unsigned long max

使用limits.h头文件中的预定义值或std::numeric_limits时,还需要将其与左侧的类型一起重写。

5 个答案:

答案 0 :(得分:29)

关于整数的转换,C 2011 [草案N1570] 6.3.1.3 2说

  

否则,如果新类型是无符号的,则通过重复地添加或减去一个可以在新类型中表示的最大值来转换该值,直到该值在新类型的范围内。

因此,将-1转换为无符号整数类型必然会产生该类型的最大值。

在各种情况下使用-1可能会出现问题,因为它不会立即转换为所需的类型。如果立即将其转换为所需的无符号整数类型(如赋值或显式转换),则结果清晰。但是,如果它是表达式的一部分,则其类型为int,并且在转换之前其行为类似于int。相比之下,UINT_MAX的类型为unsigned int,因此其行为类似于unsigned int

正如chux在评论中指出的那样,USHRT_MAX实际上有int类型,因此即使命名限制也不能完全避免类型问题。

答案 1 :(得分:16)

  

-1是否正确用作无符号整数的最大值?

是的,当用作直接分配/初始化时,它在功能上是正确的。然而,经常看起来有问题@Ron

来自limits.hstd::numeric_limits的常量会传达更多代码理解,但如果i的类型发生变化,则需要维护。

[注意] OP后来删除 C 标记。

添加一个替代方案来分配最大值(在C11中可用),这有助于减少代码维护:

使用所爱/恨_Generic

#define info_max(X) _Generic((X), \
  long double: LDBL_MAX, \
  double: DBL_MAX, \
  float: FLT_MAX, \
  unsigned long long: ULLONG_MAX, \
  long long: LLONG_MAX, \
  unsigned long: ULONG_MAX, \
  long: LONG_MAX, \
  unsigned: UINT_MAX, \
  int: INT_MAX, \
  unsigned short: USHRT_MAX, \
  short: SHRT_MAX, \
  unsigned char: UCHAR_MAX, \
  signed char: SCHAR_MAX, \
  char: CHAR_MAX, \
  _Bool: 1, \
  default: 1/0 \
  )

int main() {
  ...
  some_basic_type i = info_max(i);
  ...
}

上述宏info_max()size_tintmax_t等类型方面存在限制,可能无法在上面的列表中列举。还有更复杂的宏可以解决这个问题。这里的想法是说明性的。

答案 2 :(得分:15)

不使用标准方式或不清楚显示意图通常是我们以后付款的坏主意

我建议:

auto i = std::numeric_limits<unsigned int>::max(); 
  

或@jamesdin建议一个更好的,更接近C   习惯:

unsigned int i = std::numeric_limits<decltype(i)>::max(); 

您的同事论点不予受理。正在更改int - &gt; long int,如下:

auto i = std::numeric_limits<unsigned long int>::max(); 
    -1解决方案相比,
  • 不需要额外的工作(感谢使用auto)。
  • &#39; -1&#39;解决方案并不直接反映我们的意图,因此可能产生有害后果。请考虑以下代码段:

using index_t = unsigned int;

... now in another file (or far away from the previous line) ...

const index_t max_index = -1;

首先,我们不明白为什么max_index-1。 最糟糕的是,如果有人想改进代码并定义

 using index_t = ptrdiff_t;

=&GT;那么语句max_index=-1不再是max ,你会得到一个错误的代码。再一次,这不可能发生在:

const index_t max_index = std::numeric_limits<index_t>::max();

CAVEAT:但使用std::numeric_limits时仍有一点需要注意。它与整数无关,但与浮点数有关。

std::cout << "\ndouble lowest: "
          << std::numeric_limits<double>::lowest()
          << "\ndouble min   : "
          << std::numeric_limits<double>::min() << '\n';

打印:

double lowest: -1.79769e+308    
double min   :  2.22507e-308  <-- maybe you expected -1.79769e+308 here!
  • min返回给定类型的最小有限值
  • lowest返回给定类型的最低有限值

总是很有意思,因为如果我们不注意(使用min而不是lowest),它可能会成为bug的来源。

答案 3 :(得分:9)

技术方面已被其他答案所涵盖;当你专注于你的问题中的技术正确性时,再次指出清洁方面很重要,因为imo这是更重要的一点。

使用该特定技巧的主要原因为什么糟糕的主意代码含糊不清。目前还不清楚是否有人故意使用未签名的欺骗或犯了错误,实际上想要将签名变量初始化为-1。如果你的同事在提出这个论点后提到评论,请告诉他不要再傻了。 :)

我实际上有点困惑,甚至有人会认真考虑这个伎俩。在C:_MAX宏中设置值达到最大值是一种明确,直观和惯用的方法。在C ++中还有一种额外的,同样毫不含糊,直观和惯用的方式,它提供了更多的类型安全性:numeric_limits。那个-1技巧是一个聪明的经典案例。

答案 4 :(得分:8)

C ++标准说明signedunsigned次转化([conv.integral]/2):

  

如果目标类型是无符号的,则结果值是与源整数一致的最小无符号整数(模数)   2 n 其中 n 是用于表示无符号类型的位数)。 [注意:在二进制补码表示中,此转换是概念性的,位模式没有变化(如果没有截断)。 - 结束记录]

是的,将 -1 转换为 n 位无符号整数将始终为您提供 2 n < / sup> -1 ,无论哪个有符号整数类型,-1都以。

开头

unsigned x = -1;是否比unsigned x = UINT_MAX;更具可读性或更低的可读性是另一种讨论(肯定有机会提升某些当你稍后查看自己的代码时,甚至可能是你自己的眉毛;)。