如果使用无符号整数,则通过减去1将基于1的编号转换为基于0的编号是否安全

Is it safe to shift 1-based numbering to 0-based numbering by subtracting 1 if unsigned integers are used?

本文关键字:编号 转换 安全 是否 无符号整数 如果      更新时间:2023-10-16

在我维护的系统中,用户从基于1的索引方案中请求集合中的元素。值存储在C++/C中基于0的数组中。

如果错误地输入0作为此函数的输入,以下假设代码是否可移植?在将基于1的编号方案转换为基于0的编号方案时,是否有更好的方法来验证用户的输入?

const unsigned int arraySize;
SomeType array[arraySize];    
SomeType GetFromArray( unsigned int oneBasedIndex )
{
  unsigned int zeroBasedIndex = oneBasedIndex - 1;
  //Intent is to check for a valid index.
  if( zeroBasedIndex < arraySize )
  {
    return array[zeroBasedIndex];
  }
  //else... handle the error
}

我的假设是(unsigned int)( 0 - 1 )总是大于arraySize;这是真的吗?

正如一些人在下面的回答中所建议的那样,另一种选择是检查oneBasedIndex并确保其大于0:

const unsigned int arraySize;
SomeType array[arraySize];    
SomeType GetFromArray( unsigned int oneBasedIndex )
{
  if( oneBasedIndex > 0 && oneBasedIndex <= arraySize )
  {
    return array[oneBasedIndex - 1];
  }
  //else... handle the error
}

对于无符号类型,0-1是该类型的最大值,因此它始终是>= arraySize。换句话说,是的,那是绝对安全的。

无符号整数在C++和C中从不溢出。

对于C++语言:

(C++11,3.9.1p4)"声明为无符号的无符号整数应遵守算术模2n定律,其中n是该特定大小整数的值表示中的位数。46)"

和脚注46):

"46)这意味着无符号算术不会溢出,因为无法由结果的无符号整数类型表示的结果被模减为比结果的无签名整数类型所能表示的最大值大一的数字。"

对于C语言:

(C11,6.2.5p9)"涉及无符号操作数的计算永远不会溢出,因为无法由生成的无符号整数类型表示的结果是降模-比最大值大一的数字由结果类型表示。"

它很可能是安全的,但对于许多目的来说,有一种更简单的方法:在数组中分配一个额外的位置,然后忽略元素0。

否,例如0-1在4字节无符号int中是0xffffffff,如果您的数组真的那么大呢?32位是可以的,因为0xffffff超过了限制,如果数组那么大,在64位编译时代码会中断。

只需检查一个BasedIndex>0

确保oneBasedIndex大于零。。。