计算机系统基础摘记——c语言数值常量的类型

1 c编译器怎么确定数值常量的类型

首先明确一下这里所说的数值常量指的是程序中的一个数字,比如:

if (1 < 2)
{
}

其中12就是数值常量。

就以数字1为例,1在很多类型的表示范围之内,比如shortintunsigned int等,那么编译器会将1解读成哪个类型呢?这是由c标准规定的,对于不同版本的c标准,相关规定的具体内容有所差异,对于c90,相关规定如下表所示:

范围类型
0~231-1int
231~232-1unsigned int
232~263-1long long
263~264-1unsigned long long

而对于c99,相关标准有了些变化:

范围类型
0~231-1int
231~263-1long long
263~264-1unsigned long long

细心的同学可能会发现,上表中没有给出负值的情况,比如-10。编译器在遇到负值的时候,先不看符号,而是根据数字来确定类型,然后再处理负号。仍旧拿-10打比方,编译器根据10来确定类型为int,然后再处理负号。

2 c语言数值常量的陷阱

为什么要强调数值常量的类型呢?因为这里面有一些陷阱需要注意。以c90标准来说,考虑如下的表达式:

-2147483648 < 2147483647

很多人第一反应都是这个表达式为true,毕竟从数值上看这是显然的。但是,支持c90标准的编译器可不这么认为!关键是-2147483648,编译器根据2147483648也就是231,确定这个数值的类型为unsigned int。再考虑负号,根据负数的补码的转换规则:对应正数(绝对值)按位取反再加1

8000_0000 按位取反⇒ 7fff_ffff 再加1⇒ 8000_0000

就这样,编译器把-2147483648硬是给处理成了unsigned int类型的2147483648,而2147483648是大于2147483647的。但是编译器又不能把2147483648解读成int类型,因为补码表示是不对称的,int类型最小可以表示到-2147483648,但最大只能表示到2147483647。如果能把2147483648表示成更大的有符号类型比如long long就不会有上述问题了,c99标准正是这么做的。不过为了写出不同版本的标准下,行为一致的程序,我们还是要注意这个细节。

为了加深理解,不妨再来看几个例子(仍然根据c90标准):
例1

int i = -2147483648;
if (i < 2147483647)
{
	printf("-2147483648 < 2147483647\n")
}

此时,会打印出-2147483648 < 2147483647。上文已说过,编译器会把-2147483648解读成一串二进制0x8000_0000 ,因此变量i所在内存存储的也是这一串二进制,但不同的是,因为i是int类型,因此会以int来看待这串二进制,一个负数自然是小于2147483647的。

例2

-2147483647 - 1 < 2147483647

对于-2147483647,编译器根据2147483647确定其为int类型,然后处理负号:

7fff_ffff 按位取反⇒ 8000_0000 再加1⇒ 8000_0001

-2147483647 - 1则得到8000_0001 - 1 = 8000_0000,由于是按int类型来看,因此8000_0000是一个负数,且是int所能表达的最小负数-2147483648。所以例2的表达式为true。值得一提的是,INT_MIN通常就定义为:

#define INT_MIN (-2147483647 - 1)

这样一来,这个宏不管在c90还是c99标准都能工作的很好。

例3

if (-2147483648 - 1 == 2147483647)
{
	printf("-2147483648 - 1 == 2147483647\n")
}

编译器会将-2147483648解读成unsigned int类型的二进制串8000_0000,而8000_0000 - 1 = 7fff_ffff,因此例3中条件成立,会执行printf语句。

3 有符号数和无符号数在一起运算

除了让编译器自己去解读数值常量的类型,我们还可以通过在数值常量后面加上后缀来主动告诉编译器数值常量的类型。比如0U0u就是告诉编译器,这是一个unsigned int0。此外,也可以用强制类型转换来实现这一目标,比如(unsigned)0

值得关注的是,当无符号数和有符号数一起运算时,c语言会进行类型提升,把有符号数按照无符号数看待。不同类型的数混在一起运算时,有一些值得注意的地方,如下表:

关系表达式类型结果说明
0 == 0U无符号true0000_0000 == 0000_0000
-1 < 0有符号true-1 < 0
-1 < 0U无符号falseffff_ffff > 0000_0000
2147483647 > -2147483647 - 1有符号true231-1 > -231
2147483647U > -2147483647 - 1无符号false231-1 < 231
2147483647 > (int)2147483648U有符号true231-1 > -231
-1 > -2有符号true-1 > -2
(unsigned)-1 > -2无符号true231-1 > 231-2

参考文献

[1] 南大袁春风教授的计算机系统基础课程

  • 2
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值