C中的文字和变量有什​​么区别(有符号和无符号短整数)?

Ali*_*iba 8 c bit-manipulation integer-promotion twos-complement unsigned-integer

我已经看到了这本书将以下代码计算机系统:一个程序员的角度来看,2/E.这很好用,并创建所需的输出.输出可以通过有符号和无符号表示的区别来解释.

#include<stdio.h>
int main() {
    if (-1 < 0u) {
        printf("-1 < 0u\n");
    }
    else {
        printf("-1 >= 0u\n");
    }
    return 0;
}
Run Code Online (Sandbox Code Playgroud)

-1 >= 0u但是,上面的代码产生的代码与上面的代码相同,不是!换一种说法,

#include <stdio.h>

int main() {

    unsigned short u = 0u;
    short x = -1;
    if (x < u)
        printf("-1 < 0u\n");
    else
        printf("-1 >= 0u\n");
    return 0;
}
Run Code Online (Sandbox Code Playgroud)

收益率-1 < 0u.为什么会这样?我无法解释这一点.

请注意,我已经看到像类似的问题这样,但他们不帮助.

PS.正如@Abhineet所说,这种困境可以通过改变short来解决int.但是,怎么能解释这种现象呢?换句话说,-14个字节是0xff ff ff ff2个字节0xff ff.鉴于它们被解释为2s补码unsigned,它们具有相应的4294967295和的值65535.它们都不小于0,我认为在这两种情况下,输出都需要-1 >= 0u,即x >= u.

它在小端英特尔系统上的示例输出:

简而言之:

-1 < 0u
u =
 00 00
x =
 ff ff
Run Code Online (Sandbox Code Playgroud)

对于int:

-1 >= 0u
u =
 00 00 00 00
x =
 ff ff ff ff
Run Code Online (Sandbox Code Playgroud)

Lun*_*din 10

上面的代码产生-1> = 0u

所有整数文字(数字常量)都有一个类型,因此也有一个签名.默认情况下,它们是int已签名的类型.附加u后缀后,将文字转换为unsigned int.

对于任何C表达式,其中有一个已签名的操作数和一个未被取消的操作数,balacing规则(正式地说:通常的算术转换)会隐式地将签名类型转换为unsigned.

从有符号到无符号的转换是明确定义的(6.3.1.3):

否则,如果新类型是无符号的,则通过重复地添加或减去一个可以在新类型中表示的最大值来转换该值,直到该值在新类型的范围内.

例如,对于标准二进制补码系统上的32位整数,无符号整数的最大值为2^32 - 1(4294967295,limits.h中的UINT_MAX).比最大值多一个2^32.并且-1 + 2^32 = 4294967295,因此将文字-1转换为带有值的unsigned int 4294967295.哪个大于0.


但是,当您将类型切换为short时,最终会得到一个小整数类型.这是两个例子之间的区别.只要小整数类型是表达式的一部分,整数提升规则就会隐式地将其转换为更大的int(6.3.1.1):

如果int可以表示原始类型的所有值(由宽度限制,对于位字段),则该值将转换为int; 否则,它将转换为unsigned int.这些被称为整数促销.整数促销不会更改所有其他类型.

如果short小于int给定平台(如32位和64位系统上的情况),则任何shortunsigned short将始终转换为int,因为它们可以放在一个平台内.

因此,对于表达式if (x < u),实际上最终if((int)x < (int)u)会得到预期的行为(-1小于0).

  • @AliShakiba:当你遇到不同的操作数时,你可以决定在进行比较之前将两个操作数转换为`signed`,或者将两个操作数转换为`unsigned`.由于`signed int`是"默认"类型,因此对其中一个操作数使用`unsigned`字面意味着您有理由指定此附加限定符.由于C被设计为"接近硬件",因此尝试将所有内容都安装到平台的本机字大小中是很自然的,以便能够使用适当的指令(不会"混合"操作数类型并且通常在字上运行 - 大小操作数). (2认同)
  • @AliShakiba整数提升背后的原始理由是:如果你有例如`char x = 200,char y = 200;`然后做`x + y`,那么表达式就不会溢出.整数提升虽然是C语言中的类型不一致,但多年来造成的弊大于利,因为静态隐式提升错误比简单的整数溢出错误更难找到.此外,隐式类型提升规则有点复杂,因此很多C程序员不知道它们是如何工作的,这是不幸的. (2认同)