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

Vic*_*voy 37 c++

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

我有一个谈话与我的同事,什么是更好的:使用-1最多的无符号整数,或者使用从价值limits.h还是std::numeric_limits

我已经告诉我的同事,使用预定义的最大值,limits.h或者std::numeric_limits是这样做的便携和干净的方式,然而,同事反对-1像数字限制一样可移植,而且更多,它还有一个优点:

unsigned short i = -1; // unsigned short max
Run Code Online (Sandbox Code Playgroud)

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

unsigned long i = -1; // unsigned long max
Run Code Online (Sandbox Code Playgroud)

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

Eri*_*hil 29

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

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

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

-1不能立即转换为所需类型的各种上下文中使用可能存在问题.如果立即将其转换为所需的无符号整数类型(如赋值或显式转换),则结果清晰.但是,如果它是表达式的一部分,则其类型为int,并且其行为类似于int直到转换.相比之下,UINT_MAX有类型unsigned int,所以它的行为就像一个unsigned int.

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

  • @chux:这是一个好点.指定类型; 这些宏是"表达式与表达式相同的表达式,表达式是根据整数提升转换的相应类型的对象",但这意味着"USHRT_MAX"可能是一个"int",所以如果你这样做,它可能会出现意外行为期待一个无符号类型. (2认同)

chu*_*ica 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);
  ...
}
Run Code Online (Sandbox Code Playgroud)

上面的宏info_max()有关于类型,比如限制size_t,intmax_t等等,可能无法在上面的列表中列举.还有更复杂的宏可以解决这个问题.这里的想法是说明性的.


Pic*_*ent 16

不使用标准方式或不清楚地显示意图往往是一个坏主意,我们以后付款

我会建议:

auto i = std::numeric_limits<unsigned int>::max(); 
Run Code Online (Sandbox Code Playgroud)

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

unsigned int i = std::numeric_limits<decltype(i)>::max(); 
Run Code Online (Sandbox Code Playgroud)

您的同事论点不可受理.改变int- > long int,如下:

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

.

using index_t = unsigned int;

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

const index_t max_index = -1;
Run Code Online (Sandbox Code Playgroud)

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

 using index_t = ptrdiff_t;
Run Code Online (Sandbox Code Playgroud)

=>则声明max_index=-1不是max,你会得到一个bug的代码.再次这不会发生在以下情况:

const index_t max_index = std::numeric_limits<index_t>::max();
Run Code Online (Sandbox Code Playgroud)

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

std::cout << "\ndouble lowest: "
          << std::numeric_limits<double>::lowest()
          << "\ndouble min   : "
          << std::numeric_limits<double>::min() << '\n';
Run Code Online (Sandbox Code Playgroud)

打印:

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

总是有趣的是要记住,因为如果我们不注意(使用min而不是lowest),它可能是一个bug的来源.

  • 或者:`unsigned int i = std :: numeric_limits <decltype(i)> :: max();` (2认同)

bes*_*esc 9

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

主要原因为什么它是一个糟糕的主意,以使用特定的诡计是:该代码是不明确的.目前还不清楚有人是故意使用无符号欺骗还是犯了错误,实际上是想将签名变量初始化为-1.如果你的同事在提出这个论点后提到评论,请告诉他不要再傻了.:)

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

  • @chux关于上下文的真实情况.但是我相信使用这个技巧的合法案例很少而且很远.即便如此,我也不希望以裸体形式看到它,而是用宏包裹或使用命名常量来消除歧义. (3认同)
  • 使用`_MAX`宏程序代码维护应该`i`从`unsigned short`变为`unsigned long`.`some_unsigned_type i = -1;`"技巧"不需要维护.这并不意味着`i = -1;`是一个很好的通用思想.然而,选择不傻的案例可能有意义.更大的背景需要做出正确的判断 - OP尚未提出. (2认同)
  • 我自己使用了这个技巧,虽然通常是'0 - 1`而不是`-1`.我认为这样看起来更有意. (2认同)

rus*_*tyx 8

C++标准说,这大约signedunsigned转换([conv.integral]/2):

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

所以是的,将-1转换为n位无符号整数将始终为您提供2 n -1,无论-1开始为哪个有符号整数类型.

是否unsigned x = -1;具有更多或更少的可读性unsigned x = UINT_MAX;是另一种讨论(肯定有可能引起一些人的注意,甚至可能是你自己以后查看自己的代码时的情况;).