C++ 中 main 和 function 之间的隐式转换

Implicit conversion in C++ between main and function

我有以下简单程序:

#include <iostream>
#include <stdio.h>

void SomeFunction(int a)
{
  std::cout<<"Value in function: a = "<<a<<std::endl;
}

int main(){

  size_t a(0);

  std::cout<<"Value in main: "<<a-1<<std::endl;
  SomeFunction(a-1);

  return 0;

}

执行此操作后,我得到:

Value in main: 18446744073709551615

Value in function: a = -1

我想我大概理解为什么函数得到'correct'值-1:有一个从无符号类型到有符号类型的隐式转换,即18446744073709551615(无符号)= -1(有符号)。

有没有函数取不到'correct'值的情况?

因为 size_t 类型是无符号的,减去 1 是明确定义的:

A computation involving unsigned operands can never overflow, because a result that cannot be represented by the resulting unsigned integer type is reduced modulo the number that is one greater than the largest value that can be represented by the resulting type.

但是,264-1 的结果值超出了 int 的范围,因此您会得到实现定义的行为:

[when] the new type is signed and the value cannot be represented in it, either the result is implementation-defined or an implementation-defined signal is raised.

因此,您的问题的答案是"yes":在某些平台上a的值会有所不同;在某些平台上,程序不会调用 SomeFunction,而是发出信号。

更容易比较和对比相同基本类型的signedinsigned,比如signed intunsigned int

int使用32位的系统上,unsigned int的范围是[0 - 4294967295],signed int的范围是 [-2147483647 - 2147483647].

假设您有一个 unsigned int 类型的变量,并且它的值大于 2147483647。如果将这样的变量传递给 SomeFunction,您将在函数中看到不正确的值。

相反,假设您有一个 signed int 类型的变量,并且它的值小于零。如果将此类变量传递给需要 unsigned int 的函数,您将在函数中看到不正确的值。

不在您的计算机上...但从技术上讲是的,在某些情况下可能会出错。

所有现代 PC 都使用 "two's complement" 系统进行有符号整数运算(有关详细信息,请阅读维基百科)。二进制补码有很多优点,但最大的优点之一是:有符号整数的不饱和加减与无符号整数的不饱和加减相同。只要 overflow/underflow 导致结果为 "wrap around"(即 0-1 = UINT_MAX),计算机就可以加减,甚至不知道您是将数字解释为有符号数还是有符号数未签名。

但是! C/C++ 在技术上 不需要 有符号整数的补码。还有另外两个允许的系统,称为 "sign-magnitude" 和 "one's complement"。这些是不寻常的系统,从未在古董架构和嵌入式处理器之外发现过(甚至很少出现)。但在那些系统中,有符号和无符号算术不匹配,(signed)(a+b) 不一定等于 (signed)a + (signed) b.

当你也在缩小类型时,还有一个更平凡的警告,就像 x64 上 size_tint 之间的情况一样,因为 C/C++ 不需要编译器在将超出范围的值缩小为有符号类型时遵循特定规则。这同样是语言律师的问题,而不是实际的不安全性,不过:VC++、GCC、Clang 和我知道的所有其他编译器通过截断缩小范围,导致预期的行为。