[栖岸计划]智英带你学C语言(第...

物理
[栖岸计划]智英带你学C语言(第三章)

用户头像
暂缓开通站点增加啦! 更新于2026-5-30 14:30:35

返回目录:[栖岸计划]智英带你学C语言(新版回归)

第三章 变量

3.1 整型变量

C语言中的整型变量有很多种,区别主要在于能否表示负数(即是否有正负号),以及表示整数的大小范围。根据是否有符号,我们可以分为signed和unsigned。通常情况下,signed可以省略。

我们知道,计算机以二进制的方式存储数据。所以,使用 $n$ 比特的存储空间就可以表示出 $2^n$ 种不同的数。下面给出常用的几种整型变量,它们通常需要的存储空间如下:

char:1字节,即8比特;

short:2字节,即16比特;

int:4字节,即32比特;(注:一些古老的机器上,int只占2字节,不过现在基本见不到了)

long:存在不同标准,一般为4/8字节,即32/64比特;

long long:8字节,即64比特。

对于无符号整数,由其二进制表示推算表示的整数方法如下:

将最低位记为第0位,从低往高,如果第 $i$ 位的值是1,那么表示的数就应该要加上 $2^i$ 。

例如,我们考虑

unsigned char a = 0b10011011;

这里0b表示后面的内容是二进制数。从低往高,第0, 1, 3, 4, 7位的值为1,故a表示的整数就是

 $2^0+2^1+2^3+2^4+2^7=155$ 。

我们验证一下:

image.png

对于有符号整数,情况要更为复杂,下面详细展开:

我们规定,有符号整数的最高位为符号位,值为0表示为正数,值为1表示为负数。如果变量为 $n$ 位,那么绝对值不超过 $2^{n-1}-1$ 的整数,均可以用除了最高位以外的部分进行编码,方法同上。

例如,因为7是正数,所以其符号位为0,而 $7=2^0+2^1+2^2$ ,其对应的编码就是00000111;-7是负数,其符号位为1,其对应的编码就是10000111。这种编码被称为原码。

实际的运算过程中,原码会带来很大的不便。例如,7+(-7)=0,这点在数学上是显然的;但是我们比较这三个数的原码:

7:00000111

-7:10000111

0:00000000

我们发现,直接类比竖式计算,对7和-7的原码相加,得到的结果并不是0。为了避免类似问题的出现,引入反码和补码:

对于正数,反码和补码都等于原码;

对于负数,反码是将原码除符号位的部分按位取反,补码等于反码加1。

例如,前面提到,-7的原码是10000111,将除了最高位的每一位按位取反,得到其反码为11111000;再将其加上1,就得到其补码为11111001。我们与7相加:

7:00000111

-7:11111001

类比竖式,相加之后每一位都是0。(最高位当然不会再往上进位,否则就不是“最高位”了。)可以说明,对于不超出存储范围的计算,结果都是正确的。这点对计算机非常有利。所以,计算机内一般都使用补码存储有符号整数。

对比上面,如果考虑

char a = 0b10011011;

那么我们由补码反推原码,并得到对应的整数。将上述过程倒过来即可。

将数减去1,得到10011010;除了最高位,每位按位取反,得到11100101;再将除了最高位,其他值为1的位表示的数加在一起:

 $2^0+2^2+2^5+2^6=101$ 。

所以a存储的数就是-101。

我们验证一下:

image.png

没有问题。

使用上面的方法,有一个小问题,即:符号位是1,但其余所有位都是0的编码不表示任何一个数。因此我们规定:对于这种情况,如果是 $n$ 位整数,表示的数就是 $-2^{n-1}$ 。

例如,我们考虑

char a = 0b10000000;

char是8位整数,所以a存储的值就是 $-2^7=-128$ 。验证一下:

image.png

因此,我们通过这种方式,用n位整数表示了 $-2^{n-1}$ 到 $2^{n-1}-1$ 之间的所有整数。

在头文件limits.h中,存有无符号整数能存储的最大值,以及有符号整数能存储的最大和最小值。通过如图的程序,可以查看这些整型变量的存储范围:

image.png

输出结果如下:

CHAR_MAX: 127

CHAR_MIN: -128

SHRT_MAX: 32767

SHRT_MIN: -32768

INT_MAX: 2147483647

INT_MIN: -2147483648

LONG_MAX: 2147483647

LONG_MIN: -2147483648

LLONG_MAX: 9223372036854775807

LLONG_MIN: -9223372036854775808

UCHAR_MAX: 255

USHRT_MAX: 65535

UINT_MAX: 4294967295

ULONG_MAX: 4294967295

ULLONG_MAX: 18446744073709551615

(LONG_MAX, LONG_MIN, ULONG_MAX可能受标准影响)

一般来讲,我们要控制数据以及它们运算得到的值不能超出上面说的范围。例如,对两个int类型变量作加法时,就必须尽量让和不大于INT_MAX,不小于INT_MIN。那如果突破了这个界限会发生什么呢?我们来看一下:

image.png

当我们把INT_MAX加上1之后,得到的是一个很小的负数,刚好是INT_MIN。类似地,把LLONG_MAX加上1之后,得到的是LLONG_MIN。这仅仅是加法,如果是乘法,我们可能会得到一些看似没有意义的数值:

image.png

当然,我们知道,INT_MAX乘以它自己绝对不可能等于1。

这种现象出现的原因是什么呢?因为存储数据范围的限制,当数学${\displaystyle}$运算的结果超出范围时,程序运算得到的输出与之并不相等。超出存储范围的更高位,在计算结果中完全“消失”了。我们将这种现象称为“溢出”。绝大多数情况下,这一现象都对程序编写是不利的,可能会导致许多超出预期的行为。因此,在编程时,一定要选取合适的变量类型存储数据。

(当然,有时我们也会利用溢出这一特性来简化很多问题。例如,当我们不关心某个巨大数字的具体值,只关心它模 $2^{32}$ 的余数的话,我们就可以使用unsigned int来存储。这么做可行的原因是很好理解的,大家可以自己分析)

收起
2
1
共1条回复
时间正序
用户头像
即未用户 3347
4小时前
原码这里打错了,7和-7打成1和-1了

Screenshot_20260530-221733.png

3条评论
用户头像
暂缓开通站点增加啦!
4小时前

已改。

用户头像
暂缓开通站点增加啦!
4小时前

牢酒声既然回来了就去更高数

别告诉我因为我更了所以你不打算写了

用户头像
即未用户 3347 回复 暂缓开通站点增加啦!
4小时前

恭喜你给了我新的理由🤓👍

然后就是最近有点忙哈,周末时间还不一定有周一到周五晚上时间多,其次就是我自己学的也不算好,目前打算是七月份下半月更(看情况会码一点字),主要以前还好,现在看的人也少了