【问题标题】:Implicit conversion confusion between signed and unsigned when reading K&R book阅读 K&R 书籍时,有符号和无符号之间的隐式转换混淆
【发布时间】:2014-02-07 12:20:51
【问题描述】:

我正在使用 K&R 书学习 c 语言。在第二章书中,作者谈到了隐式转换。书上是这么说的:

当涉及无符号操作数时,转换规则更加复杂。问题是 有符号和无符号值之间的比较取决于机器,因为它们取决于各种整数类型的大小。例如,假设 int 为 16 位,long 为 32 位。然后 -1L 1UL,因为 -1L 被提升为 unsigned long,因此看起来是一个很大的正数。

我在两种不同的场景下尝试了下面的代码:

  1. 在 x86 64 位平台上编译并执行。其中sizeof(-1L) -> 8 字节和sizeof(1U) -> 4 字节
  2. 在 x86 32 位平台上编译并执行。其中sizeof(-1L) -> 4 字节和sizeof(1U) -> 4 字节

代码:

int main() {
 if(-1L > 1U)
    printf("true");
    else
    printf("false");
    return 0;
}

结果:

  1. x86 64 位:false
  2. x86 32 位:true

所以我在每种情况下都会得到两个不同的 OP。

正如作者所说,对于 2 种不同的数据大小,一种是 16,另一种是 32,它适用于我的 x86-64 案例。

但我无法理解为什么在 32 位的第二种情况下,我得到true。 正如作者所说,unsigned int 被提升为signed long int,如果这是真的,那么两者 应该是 4 字节宽,那为什么打印 true 而不是 false?现在两者都应该是signed long

正如作者所说,它依赖于机器,那么longint 应该具有相同的字节大小,那么这里的隐式转换是如何发生的?

我的理解是-1 存储为二进制补码 0xFFFFFFFF > 0x1 所以在第二种情况下它应该是true

但这种解释与第一种情况相矛盾。

如果我认为是错误的,请纠正我,因为我是隐式转换的新手。

谁能解释一下这种行为?

【问题讨论】:

  • 不应该-1L > 1LU 在这两种情况下都评估为真?
  • 抱歉错字不是 1LU 而是 1U

标签: c implicit-conversion


【解决方案1】:

让我们先解释一下等级系统

6.3.1 Arithmetic operand(c99 standard)

A) The rank of a signed integer type shall be greater than the rank of any signed integer
type with less precision(more bytes higher precision higher rank)

B) The rank of long long int shall be greater than the rank of long int, which shall be
greater than the rank of int, which shall be greater than the rank of short int, which 
shall be greater than the rank of signed char.

C) The rank of any unsigned integer type shall equal the rank of the corresponding signed 
integer type, if any.
(in other words if your system unsigned int is 32bits and your int is 32bits then the 
ranks of these are the same.)

以上解释了排名。

现在开始算术转换。

6.3.1.8 Usual arithmetic conversions (c99 standard)

1)If both operands have the same type, then no further conversion is needed.

2)Otherwise, if both operands have signed integer types or both have unsigned integer 
 types, the operand with the type of lesser integer conversion rank is converted to the
 type of the operand with greater rank.(similar to 1)

3)Otherwise, if the operand that has unsigned integer type has rank greater or equal to  
  the rank of the type of the other operand, then the operand with signed integer type is
  converted to the type of the operand with unsigned integer type.

4)Otherwise, if the type of the operand with signed integer type can represent all of the 
  values of the type of the operand with unsigned integer type, then the operand with 
  unsigned integer type is converted to the type of the operand with signed integer type

5)Otherwise, both operands are converted to the unsigned integer type corresponding to the
  type of the operand with signed integer type.

2) 在 x86 32 位平台上编译并执行。其中 sizeof(-1L) -> 4byte 和 sizeof(1U) -> 4 bytes

在您的情况下,请查看语句 3 和 C。无符号值(4bytes)的等级等于有符号值(4btyes),因此将单值转换为无符号值,当这种情况发生时,符号位会使其看起来像一个非常大的值。 -1L > 1U 因此为真

1) 在 x86 64 位平台上编译并执行。其中 sizeof(-1L) -> 8byte 和 sizeof(1U) -> 4 bytes

在这种情况下,无符号值排名小于有符号值的排名。看4)。 有符号整数(8 字节)可以表示任何 4 字节无符号值。因此无符号的 4 字节值被转换为有符号值。(这将保留符号位,符号位为 0)

因此-1L > 1U 为假

【讨论】:

    【解决方案2】:

    但我无法理解为什么在 32 位的第二种情况下它的 OP--> 是真的。正如作者所说,unsigned int 被提升为 signed long int 如果是这样,那么两者都是 4 字节宽,为什么它的打印是 true 而不是 false。?因为现在两者都签署了很长时间。

    作者说,如果intlong 具有不同 大小,那么unsigned int 将提升为signed long

    如果intlong 具有相同的大小,则long 太小而无法容纳unsigned int 的所有值,因此两者都将转换为unsigned long

    【讨论】:

      【解决方案3】:

      对于二元算术和关系运算符:

      如果任一操作数的类型为 long double,则另一个操作数将转换为 long double。否则,如果任一操作数的类型为 double,则另一个操作数将转换为 double。否则,如果任一操作数的类型为 float,则另一个操作数将转换为 float。否则,对两个操作数都执行整数提升。

      (整型提升:char、short int 或 int 位域,或它们的有符号或无符号变体,或枚举类型,可以在可以使用 int 或 unsigned int 的表达式中使用。如果int 可以表示原始类型的所有值,该值转换为 int;否则转换为 unsigned int。)

      然后,如果任一操作数的类型为 unsigned long int,则另一个操作数将转换为 unsigned long int。否则,如果一个操作数的类型为 long int,而另一个操作数的类型为 unsigned int,如果 long int 可以表示 unsigned int 的所有值,则 unsigned int 类型的操作数将转换为 long int; 如果 long int 不能表示 unsigned int 的所有值,则两个操作数都将转换为 unsigned long int。 否则,如果任一操作数的类型为 long int,则另一个操作数将转换为 long int。否则,如果任一操作数的类型为 unsigned int,则另一个操作数将转换为 unsigned int。否则,两个操作数的类型都是 int。

      粗体字解释了第二种情况,其中 long int 与 unsigned int 具有相同的宽度,因此不能保存 unsigned int 的所有值。

      (上面的描述少了unsigned long long intlong long it这两个类型,但是规则基本一样。)

      【讨论】:

        【解决方案4】:

        由于上面所有回答的人都是正确的,只是为了增加更多的清晰度和我的理解写在这里以获得更多的清晰度。

        -->if one operand has type long int and the other has type unsigned int,

        -->if a long int can represent all values of an unsigned int the operand of type unsigned int is converted to long int;

        -->if a long int cannot represent all the values of an unsigned int, both operands are converted to unsigned long int.

        所以从上面one operand has type long int-1Lthe other has type unsigned int1U

        假设 sizeof -1L 是 --->8byte 并且 sizeof 1U 是 4 byte

        0X0000-0XFFFFF values can be represented using in long int whose sizeof is 8 byte

        所以在这种情况下 long int can represent all values of an unsigned int 即使用 8byte ---> 它可以表示所有值 unsigned int 1U

        所以---->这里operand of type unsigned int is converted to long int ---> -1L > 1U --> is false

        第二个案例

        if a long int cannot represent all the values of an unsigned int

        即 sizeof -1L -->4byte 和 sizeof 1U -->4byte

        这里 long int 不能表示所有值,即使用 4 个字节--> cannot represent 所有 unsigned int 1U 的值。所以两个操作数都是converted to unsigned long int

        -1L 与 1U 相比,因为它现在是无符号的,所以它的价值似乎很大。

        i.e---->0xFFFFFFFF > 0x1 ---> its true

        【讨论】:

          猜你喜欢
          • 2013-04-06
          • 2013-07-23
          • 2019-05-12
          • 2019-04-10
          • 1970-01-01
          • 1970-01-01
          • 2011-11-08
          • 2015-07-25
          • 1970-01-01
          相关资源
          最近更新 更多