【问题标题】:Implicit Type Conversion隐式类型转换
【发布时间】:2010-10-07 18:03:04
【问题描述】:
#include<stdio.h>
int main(void)
{ 
  signed int a=-1;
  unsigned int b=1;
  int c= a+b;
  printf("%d\n",c);

  return 0;
  }

根据隐式类型转换的规则,如果一个操作数是unsigned int,另一个操作数将转换为unsigned int,二元运算结果为unsigned int。 所以这里b是unsigned int,a应该被类型转换为unsigned int。因为unsigned int总是+ve,所以a的值将是1.soc=1+1=2。但是输出是0。怎么样?

【问题讨论】:

  • 我相信这是您正在经历的实现定义(或未定义?)的行为。
  • @strager:是的,分配给c 的行为是实现定义的。 6.3.1.3/3:“新类型是有符号的,值不能在其中表示;结果要么是实现定义的,要么是产生实现定义的信号。”
  • 你们都错了。相关的转换是从有符号到无符号,不是无符号到有符号,并且行为是明确定义的。 -1 以 UINT_MAX+1 为模减少,得到 UINT_MAX,再将 1 加到 UINT_MAX+1 以减少模,因此为 0。然后将 0 转换回有符号类型是明确定义的。
  • @R.没错,使用这些值定义了它。出于某种原因[编辑:我找到了原因 - 因为 Parixit 在评论中提供了第二个示例] 我正在考虑将无符号算术的结果存储在有符号值中的一般情况。

标签: c


【解决方案1】:

-1,当转换为无符号时,将成为该类型的最大可能值——例如使用 32 位无符号,它将是 4,294,967,295。当您向其中添加 1 时,该值“环绕”为 0。

【讨论】:

  • @Jerry Coffin 因此,如果我采用有符号 int a= -2 和无符号 b=1,那么输出将为 4,294,967,295?但输出为 -1。
  • %d 输出一个有符号整数。试试 %u。
  • @Parixit:是的,因为 c 已签名。
  • @Parixit c 又是一个签名值,这就是您要打印的内容,因此您会看到签名表示。
  • 您将结果放入一个有符号整数,它不能表示该值。它采用相同的位模式(全为)并将其视为带符号的 int,即为 -1。如果您将c 设为无符号并使用“%u”转换格式,您将获得无符号值。
【解决方案2】:

"a 应该被强制转换为 unsigned int。因为 unsigned int 总是 +ve ,所以 a 的值为 1。"

更正至“将是”,但此后不正确;-)

将有符号整数转换为无符号整数的结果在标准 6.3.1.3/2 中指定:

如果新类型是无符号的,则值 通过重复添加或转换 比最大值减一 可以表示的值 新类型,直到值在 新类型的范围

换句话说,负值通过取其值以 2 的某个幂为模,而不是通过翻转符号来转换为无符号。

【讨论】:

  • 不,因为 -1 不能表示为 unsigned int,所以它不能是将任何内容转换为 unsigned int 的结果。标准中有一个脚注说“加法”或“减法”是指所涉及的实际数学数字,而不是任何特定 C 类型的 + 或 - 运算符。这同样适用于我对“模”的使用——我的意思是数学运算,产生一个在[0,UINT_MAX] 范围内的值。我不是指签名的% 运算符。
  • 也就是说,作为一名受过教育的数学家,我个人有时确实认为无符号值是环模 UINT_MAX 的抽象成员。在这种情况下,是的,以 UINT_MAX+1 为模减少 -1 的结果仍然是 -1,但在 -1 等于 UINT_MAX 的模型中。但是,将此作为无符号整数的心智模型可能并不明智,因为该模型无法描述某些 C 操作,例如除法。
【解决方案3】:

现代机器大多使用two's complement 表示负数。当两个数字相加时,如果其中任何一个为负数,则首先将其转换为二进制补码表示。然后这两个数字将相加。所以计算机通常将1 - 1 执行为1 + two's complement of (-1)。结果为 0。

对于1 - 2,它是1 + two's complement(-2)。检查这个程序,相同的编号,不同的表示:

int main()
{
    signed int a = 1;
    unsigned int b = -2;

    int c = a+b;

    printf("%d\n%u\n", c, c);

    return 0;
}

请阅读二进制补码表示。你需要它才能成为一名程序员。

【讨论】:

  • 加法的行为与二进制补码表示无关。在一个人的补码机器上是一样的,直到结果被分配给c(这是实现定义的,正如strager所说)。
  • -1 二进制补码与 OP 的问题无关,它在 any C 实现上具有相同的行为。您的新示例依赖于二进制补码实现常见的特定于实现的行为。
  • 我的目的是让 OP 了解最常见的实现。抱歉,我应该在原始答案中注明。
猜你喜欢
  • 2013-07-09
  • 2012-01-21
  • 2018-02-21
  • 1970-01-01
  • 1970-01-01
  • 2011-07-01
  • 1970-01-01
  • 2011-05-08
  • 2021-06-08
相关资源
最近更新 更多