为什么C++在表达式中将有符号的 int 转换为无符号的 int

Why does C++ converts a signed int to an unsigned int in an expression?

本文关键字:int 转换 无符号 符号 C++ 表达式 为什么      更新时间:2023-10-16

当将intunsigned int进行比较时,例如:

signed int si = -1;
unsigned int ui = 0;
if (ui > si)
{
    // Do something
}

si将转换为unsigned int,因此它将大于ui 。那么,如果结果不会像预期的那样,为什么还要允许这样做,是出于历史原因,如果他们不得不再次这样做,他们不会允许这样做?

C++具有以下规则,用于确定在完成整数升级后将两个值转换为的类型(第 5 章,第 9 条):

  • 如果两个操作数的类型相同,则无需进一步转换。
  • 否则,如果两个操作数都具有有符号整数类型
  • 或都具有无符号整数类型,则整数转换秩较小的操作数应转换为具有较大秩的操作数的类型。
  • 否则,如果具有无符号整数类型的操作数
  • 的秩大于或等于其他操作数类型的秩,则具有有符号整数类型的操作数应转换为具有无符号整数类型的操作数的类型。
  • 否则,如果带符号整数类型的操作数的类型可以表示无符号整数类型的操作数类型的
  • 所有值,则无符号整数类型的操作数应转换为带符号整数类型的操作数的类型。
  • 否则,两个操作数都应转换为与具有有符号整数类型的操作数类型相对应的无符号整数类型。

最后一条规则适用于此处,因为intunsigned int具有相同的等级。

此规则之所以存在,是因为它是解决问题的最佳方法。

你不能比较苹果和橙子。唯一的选项是:

  • 转换 橙子 为 苹果
  • 转换 苹果 为 橙色
  • 将两者转换为其他常见类型

在前两个选项中,将两者转换为无符号比将两者转换为有符号更有意义。

第三种选择怎么样?我想一种可能性是将两个值都转换为long然后进行比较。乍一看,这似乎是一个好主意,但如果你再考虑一下,就会有一些问题:

  • 如果longint的大小相同,那么这实际上没有帮助
  • 即使long大于int,您也只是将问题转移到将longunsigned long进行比较的情况下。
  • 编写可移植代码会更难。

最后一点很重要。 当您编写模板代码或使用重载函数的代码时,有关shortchar提升为int的历史规则实际上非常烦人,因为它会更改调用的重载。

我们不想再引入任何相同类型的规则(例如,如果intunsigned int相比,则将其提升为long,但前提是sizeof(long)> sizeof(int) yada yada yada)。

原因主要是历史原因。即使在今天,C++与 C 代码兼容也很重要。你可以采用一个 C 代码库并将其逐字转换为 C++ 它可能会起作用,即使存在一些细微的差异和不兼容性。C 以这种方式定义它,C++不会更改它,否则它会改变代码的含义,从而破坏本来可以工作的程序。

在当前的工作草案(N4296)中,您可以在第5.10.5节中找到规则。

该语言只有两种选择:

  • 将已签名视为未签名
  • 将未签名视为已签名

正如达斯布林肯莱特所说,语言要求前者。原因是它使代码更简单。在现代机器中,顶部位是符号位,硬件可以执行有符号或无符号比较,因此代码只是一个比较,然后是无符号条件跳转。

若要将未签名视为已签名,编译器可以丢弃(屏蔽)无符号单词 UI 中的顶部位,然后执行已签名测试,但这会更改其值。或者,它可以先测试 ui 的顶部位,如果设置,则返回更大的内容,然后执行上述掩码。

最重要的是,选择语言是因为它的代码效率更高。