【问题标题】:C usual arithmetic conversionsC 常用算术转换
【发布时间】:2023-03-23 02:52:01
【问题描述】:

我正在阅读有关常用算术转换的 C99 标准。

如果两个操作数的类型相同,则不再进行转换 需要。

否则,如果两个操作数都具有有符号整数类型或都具有 无符号整数类型,具有较小整数类型的操作数 转换等级转换为具有更大的操作数的类型 排名。

否则,如果无符号整数类型的操作数有秩 大于或等于另一个操作数的类型的等级,则 带符号整数类型的操作数转换为 无符号整数类型的操作数。

否则,如果带符号整数类型的操作数的类型可以 用无符号表示操作数类型的所有值 整数类型,然后转换无符号整数类型的操作数 为有符号整数类型的操作数的类型。

否则,两个操作数都转换为无符号整数类型 对应带符号整数类型的操作数的类型。

假设我有以下代码:

#include <stdio.h>

int main()
{
    unsigned int a = 10;
    signed int b = -5;

    printf("%d\n", a + b); /* 5 */
    printf("%u\n", a + b); /* 5 */
    return 0;
}

我认为加粗的段落适用(因为 unsigned intsigned int 具有相同的排名。为什么 b 不转换为 unsigned ?或者它可能转换为无符号但有一些我不明白?

感谢您的宝贵时间 :-)

【问题讨论】:

  • 是什么让您认为b 没有转换为unsigned
  • @Charles Bailey 我想我愚蠢地期待 printfs 的不同结果:-?
  • +5 是 +5,无论 int 是有符号还是无符号。
  • 感谢所有提供帮助的人(没有足够的代表 +1):-)
  • @user963368:您传递给printf 的格式说明符应该与相应参数的类型匹配。如果你弄错了,编译器不会告诉你。此外,加法的结果在intunsigned int的可表示范围内,因此在这两种类型中应该具有相同的表示。

标签: c integer


【解决方案1】:

确实b 转换为无符号。但是您观察到的是 b 转换为无符号,然后添加到 10 给出的值为 5。

在 x86 32 位上会发生这种情况

  1. b,转换为无符号,变为4294967291(即2**32 - 5
  2. 添加 10 变为 5,因为在 2**32 (2**32 - 5 + 10 = 2**32 + 5 = 5) 处环绕

【讨论】:

  • 感谢您的回答。遗憾的是,我没有足够的代表 +1。
【解决方案2】:

0x0000000a 加上 0xfffffffb 将始终为 0x00000005,无论您处理的是有符号还是无符号类型,只要只使用 32 位即可。

【讨论】:

  • 所以你的意思是它溢出并以2^32为模减少?
  • 它溢出了,结果看起来好像已经应用了模数。
  • 实际上,对于 C 标准,溢出 signed 整数是未定义的行为(即使今天我确实希望每个硬件都使用整数的 2 补码表示)。
  • @IgnacioVazquez-Abrams C 标准说整数溢出的行为是未定义的。根据标准,只有带符号的算术溢出。无符号算术不会溢出,它总是模块化的。
【解决方案3】:

从问题中重复代码的相关部分:

unsigned int a = 10;
signed int b = -5;

printf("%d\n", a + b); /* 5 */
printf("%u\n", a + b); /* 5 */

a + b 中,b 被转换为无符号整数,(根据无符号到有符号转换的规则产生 UINT_MAX + 1 - 5)。根据无符号算术规则,该值加 10 的结果为 5,其类型为无符号整数。在大多数情况下,C 表达式的类型与它出现的上下文无关。 (请注意,这些都不依赖于表示形式;转换和算术纯粹是根据数值来定义的。)

对于第二个printf 调用,结果很简单:"%u" 需要一个unsigned int 类型的参数,而你已经给了它一个。它打印"5\n"

第一个printf 有点复杂。 "%d" 需要一个 int 类型的参数,但是你给它一个 unsigned int 类型的参数。在大多数情况下,像这样的类型不匹配会导致未定义的行为,但是有一个特殊情况规则,相应的有符号和无符号类型可以作为函数参数互换——只要值在两种类型中都是可表示的(就像这里一样) .所以第一个printf 也会打印"5\n"

同样,所有这些行为都是根据值而不是表示来定义的(除了要求给定值在相应的有符号和无符号类型中具有相同的表示)。在有符号整数和无符号整数都是 37 位、有符号整数有 7 个填充位、无符号整数有 11 个填充位且有符号整数使用 1s'-complement 或 sign-and-magnitude 的系统上,您会得到相同的结果表示。 (据我所知,现实生活中不存在这样的系统。)

【讨论】:

    【解决方案4】:

    它被转换为unsigned,无符号算术恰好给出了你看到的结果。 无符号算术的结果相当于用二进制补码进行有符号算术,并且没有超出范围的异常。

    【讨论】:

    • 你说的是无符号溢出吗?
    • unsigned 不会溢出(就标准而言),而只是环绕。这在标准中有很好的定义。
    猜你喜欢
    • 1970-01-01
    • 2014-08-22
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-03-31
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多