【问题标题】:Why is comparing a signed char and unsigned int not working right?为什么比较有符号字符和无符号整数不能正常工作?
【发布时间】:2012-01-28 21:35:29
【问题描述】:

我写了一小段代码来测试一些东西:

#include <stdio.h>

int main()
{
    unsigned  x = 1;
    signed char y = -1 ;
    if (x>y)
        printf("X > Y");
    else
        printf("X <= Y");
    return 0;
}

我得到的输出是“X -1 吗?

【问题讨论】:

  • 将 -1 分配给有符号变量是行不通的。
  • 欢迎来到 StackOverflow。请使用正确的英语句子,例如“为什么我会得到这个输出?”而不是 SMS-speak “Y 我得到这个输出了吗?”。另请阅读FAQ,尤其是How do I ask questions here?部分
  • @talonmies - 当然会。签名意味着你可以有一个标志。
  • @QuentinUK - 实际上,unsigned x 默认为 int,所以它将是 -2^31
  • @polynomial,我想可能是这样,这就是为什么我只发表评论而不是回答。

标签: c


【解决方案1】:

我们有:

unsigned  x = 1;
signed char y = -1;

这个表达式:

x > y

用作if语句的控制表达式。

在通常的算术转换之后,右操作数y 将被转换为unsigned int 值。负的signed char-1 的转换结果将是一个巨大的unsigned int 值(等于UINT_MAX)。

所以表达式x &gt; y 将被计算为:

1U > UINT_MAX

始终为假(即,评估为 0)。

这是简短的版本。为了解释我们如何用 C 标准规则得出这个结果,我在下面解释一下。

事情是这样的:

使用了&gt;关系运算符,这里是C对关系运算符的说法:

关系运算符 (C99, 6.5.8p3) “如果两个操作数都具有算术类型,则执行通常的算术转换。”

好的,在我们的示例中,操作数都是整数类型,整数类型是算术类型。所以通常的算术转换将完成。常用的算术转换有哪些?

通常的算术转换 (C99, 6.3.1.8p1) "否则,对两个操作数都执行整数提升。然后将以下规则应用于提升的操作数:`

好的,第一个整数提升是在每个操作数上完成的。整数促销如何执行?

整数提升 (C99, 6.3.1.1p2) "如果一个int可以表示原始类型的所有值,则将该值转换为int;否则,将其转换为unsigned int . 这些被称为整数提升。”

y 属于 signed char 类型,因此在整数提升之后它首先被提升为 int,而 x 属于 unsigned int 类型并保持为 unsigned int

然后通常的算术转换会在两个操作数之间找到一个共同的类型。在我们的例子中,这意味着:

常用算术转换(套件) (C99, 6.3.1.8p1) “否则,两个操作数都转换为无符号整数类型,对应于带符号整数类型的操作数类型。”

unsigned intint 类型具有相同的转化排名(记住signed char 被提升为int),因此提升的y 将从int(提升后)转换为@987654344 @。有关信息,整数转换等级在 (C99, 6.3.1.1p1) 中定义。 如您所见,unsigned int 在通常的算术转换中胜过int,另一种说法是unsigned粘性

现在如何将-1int 值(提升为int 后的signed char -1)转换为unsigned int 值?`。以下是 C 在这种特定情况下关于整数转换的说法:

整数转换 (C99, 6.3.1.3p2) "否则,如果新类型是无符号的,则通过重复加或减1来转换该值,而不是可以表示的最大值新类型,直到值在新类型的范围内。”

这一段是这样写的,所以它的含义保持独立于带符号的数字表示。对于二进制补码表示,这意味着将int-1 转换为(UINT_MAX + 1) - 1,等于UINT_MAX。所以在我们的具体案例中,

x > y

等价于

1U > UINT_MAX

等价于

0

【讨论】:

    【解决方案2】:

    如果您比较不同类型的变量,则必须在比较完成之前将其中一个强制转换为另一个的类型。

    “较短”类型将升级为“较长”类型。

    在这种情况下,signed char y 将被转换为 unsigned int,其值为 UINT_MAX

    具体来说,假设编译器使用 32 位 ints

       signed char          -1 = 0xff        becomes
    -> signed int           -1 = 0xffffffff  becomes
    -> unsigned int 0xffffffff = UINT_MAX
    

    因此x &lt; y

    【讨论】:

    • 转换是在char 端还是int 端完成的?如果是二进制,那不就是0xFF000000吗?
    • @Polynomial no - 负值得到符号扩展,所以(signed char)-1(即0xff)在转换为32位signed int时将为0xffffffff,然后在转换为无符号时结果值为UINT_MAX
    • @Alnitak - 啊,有趣。谢谢(你的)信息! :)
    【解决方案3】:

    不是 1 > -1 吗?

    是的,除非您使用 unsigned 值。在unsigned 的世界中,最小值是零和一。其他一切都更大,并且该语言明确指出unsigned(-1)最大无符号值。

    【讨论】:

    • 我想知道 unsigned 在数学上是否存在“最小值”?它的算术是模数,所以它就像一个圆。再少一个 (i--),你最终会再次到达 UINT_MAX。那么“最小”值是多少?
    • 考虑到unsigned 0 &lt; x 对于除 0 之外的所有 x 值都为真,我将 0 称为最小值。
    • 比较运算符不遵守模运算,这是有道理的,因为模运算没有顺序关系。相反,比较运算符在根据提升规则提升其参数之后始终遵循普通整数算术定律。
    猜你喜欢
    • 1970-01-01
    • 2014-01-28
    • 1970-01-01
    • 2017-10-19
    • 2021-10-31
    • 2011-07-21
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多