学科分类
目录
C语言

数据溢出

C语言中的基本数据类型占据不同的内存空间,都有一定的取值范围,如果在定义变量时,将一个超出取值范围的值赋给了变量,就会发生数据溢出。例如,字符类型变量占据的内存大小为1个字节(8bit),取值范围为-128~127,如果为字符类型变量所赋的值超出这个范围,编译器就不能正确解读这个数据,示例代码如下所示:

char ch1 = -129;     //超出下限范围,ch1的结果为127
char ch2 = -128;     //ch2结果为-128
char ch3 = 0;       //ch3结果为0
char ch4 = 127;      //ch4结果127
char ch5 = 128;      //超出上限范围,ch5结果为-128

在上述代码中,ch1与ch5在赋值时都超出了字符类型的取值范围,发生数据溢出,因此不能正确的显示结果。在赋值时,数据如果小于取值范围的最小值称为数据下溢,数据如果大于取值范围的最大值称为数据上溢。

如果读者继续在字符范围之外逐渐递增(递减)取值,则会发现一个有趣的现象,字符数据类型的取值以255(127-(-128)=255)为周期循环回绕读取数据。例如,上述代码中,为ch5赋值128,则真实读取的数据为-128,如果为ch5赋值129,则真实读取的数据为-127;如果为ch5赋值为130,则真实读取的数据为-126…,这样当为ch5赋值为383时,真实读取的数据为127,为ch5赋值为384时,真实读取数据又变回-128。该过程的示例代码如下:

ch5 = 128;    //真实读取数据为-128
ch5 = 129;    //真实读取数据为-127
ch5 = 130;    //真实读取数据为-126ch5 = 383;   //真实读取数据为127
ch5 = 384;   //真实读取数据为-128

为ch5赋值128时,其值为-128,为ch5赋值383时,其值为127。383-128=255,这正好是字符类型取值范围的周期。如果继续递增赋值,则ch5的取值又回绕进入一个新的循环,该溢出过程类似时钟的循环,如图1所示。

图1 字符数据类型数据溢出的循环回绕现象

同理,整型类型的数据也会发生溢出,而且在C语言编程中,整数数据溢出最为常见。整型类型可以分为有符号整型和无符号整型,无论是哪种整型类型,当赋值超出取值范围时都会发生回绕现象。例如,对于unsigned int类型,其取值范围0~4294967295 (0 ~ 232-1),当为unsigned int类型的变量赋值时,如果所赋值超出这个范围也会发生回绕,示例代码如下:

unsigned int num1 = -1;                //数据下溢,真实读取数据为4294967295
unsigned int num2 = 0;                 //真实读取数据为0
unsigned int num3 = 4294967295;      //真实读取数据为4294967295
unsigned int num4 = 4294967296;      //数据上溢,真实读取数据为0

需要注意的是,unsigned int类型变量在输出时以u%格式输出,输出格式将在2.4.1节讲解。

在实际编程中,想要记住不同数据类型的取值范围是很难的,为了减少编程中的数据溢出错误,C语言针对不同的整型类型都定义了一个宏,用于表示该数据类型的极值,具体如表1所示。

表1 不同整型数据类型极值宏定义

数据类型 极大值 极小值
short SHRT_MAX SHRT_MIN
int INT_MAX INT_MIN
long LONG_MAX LONG_MIN
unsigned short USHRT_MAX -
unsigned int UINT_MAX -
unsigned long ULONG_MAX -

表1中的极值宏定义包含在limits.h标准库中,使用这些宏定义需要包含该标准库。

点击此处
隐藏目录