比较有符号和无符号变量时出现意外的程序输出

时间:2015-08-27 18:02:21

标签: c

这是代码:

unsigned int c;
signed int d = -1;
c = d;
if(c == d) 
    printf("c == d\n");

运行此选项会输出: c == d

变量c不能为负吗?

6 个答案:

答案 0 :(得分:7)

根据通常的算术转换的规则,表达式c == d被解释为c == (unsigned int) d。更具体地说,当您在相等比较运算符中混合使用signed intunsigned int个操作数时,signed int操作数会在比较之前隐式转换为unsigned int类型。对于C中的大多数二元运算符也是如此。

同时,您将c的值指定为c = d,相当于c = (unsigned int) d

因此,正如您可以立即看到的那样,您将同一事物与同一事物进行比较:您实际上是在将(unsigned int) d(unsigned int) d进行比较。难怪平等成立。

答案 1 :(得分:4)

执行if(c==d)时,它会在检查前执行隐式类型转换。在类型转换之后,它们是相等的,因此表达式为真。

在回答问题时,"变量c不能为负数?"你是正确的,c不能是负面的。

答案 2 :(得分:1)

根据标准 - signed int,将转换为unsigned int。

检查

中第53页的“6.3.1.8常规算术转换”

http://www.open-std.org/jtc1/sc22/wg14/www/docs/n1570.pdf

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

分配d-1d成员0xFFFFFFFF(二人补充)

c被分配d时,c持有0xFFFFFFFF

然后您将cdif (c == d)进行比较,将两个变量比较为dword - 并且它们是相同的值 - 因此它会打印“{{ 1}}“

答案 3 :(得分:1)

确实,c不能是否定的。因此cd持有不同的值。然而,比较c==d仍被正确评估为真。

原因是它们属于不同类型。并且不能直接比较不同类型。当编译器用不同的类型包含这样的表达式时,必须遵循标准中详述的cetain规则将这些值转换为公共类型。而且这种转换可能会改变正在评估的价值。

在这种特殊情况下,这些规则表明d在评估==之前隐式转换为无符号,c按原样评估。

  • 在左侧我们有c,它已经保存了将-1转换为无符号的结果(因为c是无符号的并且被分配了d,其中包含-1) 。 c按原样评估,因此左侧评估为 -1转换为无符号
  • 在右侧,我们有d,其中包含-1。右侧通过转换为无符号进行评估,因此右侧评估为 -1转换为无符号

因此==的双方最终都被评估为 -1转换为无符号。双方都是平等的,所以expresion评估为真(1)。

注意:有些人可能会对cd拥有不同值的声明感到惊讶。但即使它们的二进制表示完全相同,也是如此。这些位可以是相同的,但它们代表的值是不同的。另请注意,不会比较那些不同的值。而是将这些值中的一个与另一个值的转换进行比较 所有这一切最终只是一个单独的CMP汇编指令,它根本没有真正转换任何东西,因为转换已经隐含在这些值存储在计算机中的方式只是一个实现细节。

答案 4 :(得分:0)

有符号和无符号的整数都只是一堆比特和字节。所以实际上-1是signed int的最大值。因此,当你分配它们时,它们将是平等的。尝试打印出c和d。

看看这个,了解签名整数的工作原理。 http://www.cs.cornell.edu/~tomf/notes/cps104/twoscomp.html

答案 5 :(得分:0)

ANSI C状态的转换规则:

[如果混合有符号和无符号值]

  

[...]   如果新类型是无符号的,则重复转换该值   加或减一个可能的最大值   以新类型表示,直到值在新范围内   类型。
  [...]

新类型是unsigned int。最大值可能是2 32 。超过最大值的是2 32 + 1.比该值增加一个以上的值是-1 + 2 32 +1,这又是2 < SUP> 32

所以c,不能包含-1,将包含2 32

现在,如果您比较cd,则在内部应用相同的转换(!)以将d与c进行比较,因为ANSI C仅比较具有相同数据类型的值,因此首先创建两个变量的相同数据类型。并且,由于执行完全相同的转换以创建两个可比较的数字,结果是正确的。

相关问题