C语言中的正负数以及数值溢出
2016-11-20 14:08
405 查看
在数学中,数字有正负之分。在C语言中也是一样,short、int、long 都可以带上符号,例如:
short a = -10; //负数 int b = +10; //正数 long c = (-9) + (+12); //负数和正数相加
如果不带正负号,默认就是正数。
符号也要在内存中体现出来。符号只有正负两种情况,用1位就足以表示,这1位就是最高位。以 int 为例,它占用32位的内存,0~30位表示数值,31 位表示正负号。如下图所示:
在编程语言中,计数往往是从0开始,例如字符串 "abc123",我们称第 0 个字符是 a,第 1 个字符是 b,第 5 个字符是 3。这和我们平时从 1 开始计数的习惯不一样,大家要慢慢适应,培养编程思维。
在符号位中,用0表示正数,用1表示负数。例如 int 类型的 -10、+16 在内存中的表示如下:
如果不希望设置符号位,可以在数据类型前面加 unsigned,如下所示:
unsigned short a = 12; unsigned int b = 1002; unsigned long c = 9892320;
这样,short、int、long 中就没有符号位了,所有的位都用来表示数值。也就意味着,使用了 unsigned 只能表示正数,不能表示负数了。
如果是
它等价于:
输出无符号数使用
#include <stdio.h>
#include <stdlib.h>
int main()
{
int a1 = 1234, a2 = -1234;
unsigned int b1 = 5678, b2 = -5678;
printf("a1=%d, a1(u)=%u\n", a1, a1);
printf("a2=%d, a2(u)=%u\n", a2, a2);
printf("b1=%d, b1(u)=%u\n", b1, b1);
printf("b2=%d, b2(u)=%u\n", b2, b2);
return 0;
}
输出结果:
a1=1234, a1(u)=1234
a2=-1234, a2(u)=4294966062
b1=5678, b1(u)=5678
b2=-5678, b2(u)=4294961618
可以发现,无论变量声明为有符号数还是无符号数,只有当以 %u 格式输出时,才会作为无符号数处理;如果声明为 unsigned 却以 d% 输出,那么也是有符号数。
a2、b2 的输出值之所以很奇怪,与它们在内存中的存储形式有关,我们将在《C语言整数在内存中是如何存储的》一节详细介绍。
最后需要说明的是:不管是否有符号,%o、%x、%X、%#o、%#x、%#X 都是以无符号形式输出,读者可以亲自测试。
当数值过大或过小时,有限的几个字节就不能表示,就会发生溢出。发生溢出时,最高位会被截去。请看下面的例子:
#include <stdio.h> int main() { unsigned int a = 0x100000000; int b = 0xffffffff; printf("a=%u, b=%d\n", a, b); return 0; }
运行结果:
a=0, b=-1
变量 a 为 int 类型,占用4个字节(32位),能表示的最大值为 0xFFFFFFFF,而 0x100000000 = 0xFFFFFFFF + 1,占用33位,已超出 a 所能表示的最大值,会发生溢出,最高位被截去,剩下的32位都是0。也就是说,在 a 被输出前,其值已经变成了 0。
对于变量 b,每一位的值都是 1,包括符号位,以 %d 输出时,按照推理应该是 -0x7fffffff = -2147483647,但是输出结果却是 -1,这是为什么呢?我们将在《C语言整数在内存中是如何存储的》一节解开谜底。
复制格式化复制
short a = -10; //负数 int b = +10; //正数 long c = (-9) + (+12); //负数和正数相加
short a = -10; //负数 int b = +10; //正数 long c = (-9) + (+12); //负数和正数相加
如果不带正负号,默认就是正数。
符号也要在内存中体现出来。符号只有正负两种情况,用1位就足以表示,这1位就是最高位。以 int 为例,它占用32位的内存,0~30位表示数值,31 位表示正负号。如下图所示:
在编程语言中,计数往往是从0开始,例如字符串 "abc123",我们称第 0 个字符是 a,第 1 个字符是 b,第 5 个字符是 3。这和我们平时从 1 开始计数的习惯不一样,大家要慢慢适应,培养编程思维。
在符号位中,用0表示正数,用1表示负数。例如 int 类型的 -10、+16 在内存中的表示如下:
如果不希望设置符号位,可以在数据类型前面加 unsigned,如下所示:
复制格式化复制
unsigned short a = 12; unsigned int b = 1002; unsigned long c = 9892320;
unsigned short a = 12; unsigned int b = 1002; unsigned long c = 9892320;
这样,short、int、long 中就没有符号位了,所有的位都用来表示数值。也就意味着,使用了 unsigned 只能表示正数,不能表示负数了。
如果是
unsigned int,那么可以省略 int ,只写 unsigned,例如:
unsigned n = 100;
它等价于:
unsigned int n = 100;
输出无符号数使用
%u,代码如下:
复制格式化复制
#include <stdio.h>
#include <stdlib.h>
int main()
{
int a1 = 1234, a2 = -1234;
unsigned int b1 = 5678, b2 = -5678;
printf("a1=%d, a1(u)=%u\n", a1, a1);
printf("a2=%d, a2(u)=%u\n", a2, a2);
printf("b1=%d, b1(u)=%u\n", b1, b1);
printf("b2=%d, b2(u)=%u\n", b2, b2);
return 0;
}
#include <stdio.h> #include <stdlib.h> int main() { int a1 = 1234, a2 = -1234; unsigned int b1 = 5678, b2 = -5678; printf("a1=%d, a1(u)=%u\n", a1, a1); printf("a2=%d, a2(u)=%u\n", a2, a2); printf("b1=%d, b1(u)=%u\n", b1, b1); printf("b2=%d, b2(u)=%u\n", b2, b2); return 0; }
输出结果:
a1=1234, a1(u)=1234
a2=-1234, a2(u)=4294966062
b1=5678, b1(u)=5678
b2=-5678, b2(u)=4294961618
可以发现,无论变量声明为有符号数还是无符号数,只有当以 %u 格式输出时,才会作为无符号数处理;如果声明为 unsigned 却以 d% 输出,那么也是有符号数。
a2、b2 的输出值之所以很奇怪,与它们在内存中的存储形式有关,我们将在《C语言整数在内存中是如何存储的》一节详细介绍。
最后需要说明的是:不管是否有符号,%o、%x、%X、%#o、%#x、%#X 都是以无符号形式输出,读者可以亲自测试。
取值范围和数据溢出
short、int、long 占用的字节数不同,所能表示的数值范围也不同。以32位平台为例,下面是它们的取值范围:数据类型 | 所占字节数 | 取值范围 |
---|---|---|
short | 2 | -32768~32767,即 -215~(215-1) |
unsigned short | 2 | 0~65535,即 0~(216-1) |
int | 4 | -2147483648~2147483647,即 -231~(231-1) |
unsigned int | 4 | 0~4294967295,即0~(232-1) |
long | 4 | -2147483648~2147483647,即 -231~(231-1) |
unsigned long | 4 | 0~4294967295,即0~(232-1) |
复制格式化复制
#include <stdio.h> int main() { unsigned int a = 0x100000000; int b = 0xffffffff; printf("a=%u, b=%d\n", a, b); return 0; }
#include <stdio.h> int main() { unsigned int a = 0x100000000; int b = 0xffffffff; printf("a=%u, b=%d\n", a, b); return 0; }
运行结果:
a=0, b=-1
变量 a 为 int 类型,占用4个字节(32位),能表示的最大值为 0xFFFFFFFF,而 0x100000000 = 0xFFFFFFFF + 1,占用33位,已超出 a 所能表示的最大值,会发生溢出,最高位被截去,剩下的32位都是0。也就是说,在 a 被输出前,其值已经变成了 0。
对于变量 b,每一位的值都是 1,包括符号位,以 %d 输出时,按照推理应该是 -0x7fffffff = -2147483647,但是输出结果却是 -1,这是为什么呢?我们将在《C语言整数在内存中是如何存储的》一节解开谜底。
相关文章推荐
- C语言中的正负数以及数值溢出
- 31 C语言中的正负数以及数值溢出
- 68 C语言数组的静态性、越界以及溢出
- 程序员之---C语言细节20(符号和有符号之间转换、两数相加溢出后数值计算)
- 程序猿之---C语言细节20(符号和有符号之间转换、两数相加溢出后数值计算)
- 内存溢出原因以及解决方案
- 用Groovy实现判断两个int数值大小(不用比较运算符,考虑溢出)
- 关于Hibernate操作数据库为空(数值类型)以及引起的问题的一点点总结
- 用C语言写的ISAPI上传文件(图片)、显示图片、图片存储以及可供其它语言调用的方式、和程序源代码
- C语言的5种存储类以及关键字volatile、restrict --主要看restrict,unix高级编程中用了好多
- 内存溢出原因以及解决方案
- C语言不通过第三个变量交换a、b两数数值的技巧
- 通过web service的方式上传附件和下载附件,以及内存溢出问题
- 详解C语言中的lib文件以及tlib命令
- 数值计算--全选主元--c语言
- 数值计算方法与算法:C语言实现利用Gauss消元法解方程组
- 请大家看一下一个c语言中的链表问题,下面的代码是有错误的!!请大家说出错误的原因,以及修改的方法!!!
- Flex :给LineChart设置坐标轴最大最小范围,以及设置纵坐标的线条间隔,数值间隔的例子
- 数值积分C语言算法
- C语言的历史以及疑点解惑