无符号和签名扩展

Sak*_*ain 10 c unsigned language-lawyer

有人可以向我解释以下代码输出:

void myprint(unsigned long a)
{
    printf("Input is %lx\n", a);
}
int main()
{
    myprint(1 << 31);
    myprint(0x80000000);
}
Run Code Online (Sandbox Code Playgroud)

输出gcc main.c:

Input is ffffffff80000000
Input is 80000000
Run Code Online (Sandbox Code Playgroud)

为什么被(1 << 31)视为签名并被0x80000000视为未签名?

M.M*_*M.M 13

在C中,表达式的结果取决于操作数(或某些操作数)的类型.特别1是,int(签名),因此1 << n也是int.

类型(包括signed-ness)0x80000000此处的规则确定,它取决于系统的大小int和其他未指定的整数类型.选择一种类型,使得0x80000000(大的正数)在该类型的范围内.

如果您有任何误解:文字0x80000000是一个大的正数.人们有时会错误地将其等同于负数,将值与表示混合在一起.

在你的问题中,你说"为什么0x80000000被视为无符号?".但是,您的代码实际上并不依赖于签名0x80000000.你唯一能做的就是将它传递给带unsigned long参数的函数.因此,无论是签名还是未签名都无关紧要; 当传递给转换时,它将转换为unsigned long具有相同值的a.(因为0x80000000它在最小保证范围内,unsigned long因此不可能超出范围).

所以,这是0x80000000处理.怎么样1 << 31?如果您的系统具有32位int(或更窄),则由于带符号的算术溢出而导致未定义的行为.(链接到进一步阅读).如果您的系统具有较大的整数,那么这将产生与该0x80000000行相同的输出.

如果你使用1u << 31而且你有32位整数,那么就没有未定义的行为,你可以保证看到程序输出80000000两次.

由于您的输出不是80000000那么我们可以断定您的系统具有32位(或更窄)的int,并且您的程序实际上导致未定义的行为.的类型的0x80000000将是unsigned int,如果int是32位的,或unsigned long以其他方式.


Moh*_*ain 6

为什么被(1 << 31)视为签名并被0x80000000视为未签名?

C.7规格中的6.5.7 Bitise移位运算符:

3对每个操作数执行整数提升.结果的类型是提升的左操作数的类型.[...]
4 E1 << E2的结果是E1左移E2位位置; 腾出的位用零填充.如果E1具有无符号类型,则结果的值为E1×2 E2,比结果类型中可表示的最大值减少一个模数.如果E1具有带符号类型和非负值,并且E1×2 E2可在结果类型中表示,那么这就是结果值; 否则,行为未定义

因此,因为1int(来自下一段中提到的6.4.4.1节),1 << 31所以intint小于或等于32位的系统上没有很好地定义该值.(甚至可能陷阱)


6.4.4.1整数常量

3十进制常数以非零数字开头,由一系列十进制数字组成.八进制常量由前缀0组成,可选地后跟一个数字0到7的序列.十六进制常量由前缀0x或0X后跟一个十进制数字序列和字母a(或A)到f(或F)分别由值10到15组成.

5整数常量的类型是相应列表中可以表示其值第一个.

Suffix   |           decimal Constant         |   Hex Constant
---------+------------------------------------+---------------------------
none     |       int                          |  int
         |       int                          |  unsigned int
         |                                    |  long int
         |       long int                     |  unsigned long int
         |                                    |  long long int
         |       long long int                |  unsigned long long int
---------+------------------------------------+---------------------------
u or U   |       unsigned int                 |  unsigned int
[...]    |       [...]                        |  [...]

所以,0x80000000与在系统上32的位或更少的位int32位或更大unsigned intunsigned int,