为什么这段C代码的输出结果应该是“no”?

6
我遇到了这个问题。
#include <stdio.h>

int main(void) {
    // your code goes here
    unsigned int i = 23;
    signed char c = -23;

    if (i > c)
        printf("yes");
    else
        printf("no");

    return 0;
}

我无法理解为什么这段代码的输出是no

有人能帮助我理解在C语言中比较运算符在比较intchar时是如何工作的吗?


4
阅读关于二进制补码以及C语言中的隐式转换(特别是算术转换)的相关内容。 - Some programmer dude
规范的来源是C标准(即N1570草案)。请参阅6.3.1.1的整数提升(将signed char值转换为int),以及6.3.1.8的通常算术转换(在执行比较之前将两个操作数转换为公共类型,unsigned int)。 - Keith Thompson
1个回答

11

你正在将一个 unsigned int 与一个 signed char 进行比较。这种比较的语义是反直觉的:涉及到 signedunsigned 操作数的大多数二进制操作都是在将带符号值转换为无符号值后,使用无符号操作数进行的(如果促进后两个操作数大小相同)。以下是步骤:

  • signed char 值被提升为与其值相同的 int,即 -23
  • 将要执行的比较是 intunsigned int 之间的比较,公共类型在 C 标准中定义为 unsigned int
  • int 被转换为值为 UINT_MAX - 23unsigned int,一个非常大的数。
  • unsigned int 值进行比较: 23 是较小的值,比较结果为假。
  • 执行 else 分支,输出 no

更糟糕的是,如果将 c 定义为 long,则结果将取决于 longint 是否具有相同的大小。 在 Windows 上,它会输出 no,而在 64 位 Linux 上,它会输出 yes

永远不要在比较中混合使用有符号和无符号值。启用编译器警告以防止这种错误(-Wall-Weverything)。最好使用 -Werror 将所有这些警告都设置为致命错误,以避免这种悲惨的代码出现。

对于完整的参考,请阅读 C 标准(C11)下的以下章节:6.3 Conversions:

  • 整型提升6.3.1.1 布尔值、字符和整数中有详细说明。
  • 操作数转换6.3.1.8 通常的算术转换中有详细介绍。

你可以从工作组网站下载C11标准的最新草案:http://www.open-std.org/jtc1/sc22/wg14/www/docs/n1570.pdf


作为这个答案的补充,以下是一个有用的参考链接:https://www.securecoding.cert.org/confluence/display/c/INT02-C.+Understand+integer+conversion+rules - chrphb
您IP地址为143.198.54.68,由于运营成本限制,当前对于免费用户的使用频率限制为每个IP每72小时10次对话,如需解除限制,请点击左下角设置图标按钮(手机用户先点击左上角菜单按钮)。 - Keith Thompson

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接