【问题标题】:Why should the output of this C code be "no"? [duplicate]为什么这个 C 代码的输出应该是“否”? [复制]
【发布时间】:2016-11-19 23:34:48
【问题描述】:
我遇到了这个问题。
#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 中对 int 和 char 进行比较时,有人可以帮助我理解比较运算符的工作原理吗?
【问题讨论】:
-
-
规范来源是C standard(即 N1570 草案)。请参阅 6.3.1.1 了解 整数提升(将 signed char 值转换为 int)和 6.3.1.8 了解 通常的算术转换(转换两个操作数到一个通用类型unsigned int,然后再进行比较)。
标签:
c
comparison-operators
unsigned-integer
【解决方案1】:
您将unsigned int 与signed char 进行比较。这种比较的语义是违反直觉的:大多数涉及signed 和unsigned 操作数的二进制操作都是在将有符号值转换为无符号后(如果两个操作数在提升后具有相同大小)对无符号操作数执行的。步骤如下:
-
signed char 值提升为具有相同值-23 的int。
- 对
int和unsigned int进行比较,常用类型为C标准中定义的unsigned int。
-
int 转换为 unsigned int,其值为 UINT_MAX - 23,这是一个非常大的数字。
- 对
unsigned int 值执行比较:23 是较小的值,比较结果为假。
- 评估
else 分支,打印no。
更糟糕的是,如果c 被定义为long,则结果将取决于long 和int 是否具有相同的大小。在 Windows 上,它将打印 no,而在 64 位 Linux 上,它将打印 yes。
切勿在比较中混合有符号和无符号值。启用编译器警告以防止此类错误(-Wall 或-Weverything)。您不妨使用-Werror 将所有这些警告设为致命,以完全避免这种命运多舛的代码。
如需完整参考,请阅读 6.3 转换下的 C 标准 (C11) 的以下部分:
-
整数提升在6.3.1.1 布尔值、字符和整数中进行了解释。
-
操作数转换在6.3.1.8 常用算术转换中有详细说明。
您可以从工作组网站下载 C11 标准的最新草案:http://www.open-std.org/jtc1/sc22/wg14/www/docs/n1570.pdf