一说到数字,我们脑子里就会闪现出一些数字的类型,比如,int,double,float,long,当然还有一些复合类型,比如
指针类型,枚举类型,结构体类型等等。关于这些类型的变量在内存中所占的字节数到底是多少,下边我来给出测试:
windows系统vs编译器下:
#define _CRT_SECURE_NO_WARNINGS 1
#include<stdio.h>
#include<stdbool.h>
int main()
{
printf("%d\n",sizeof(char));
printf("%d\n", sizeof(short));
printf("%d\n", sizeof(int));
printf("%d\n", sizeof(long));
printf("%d\n", sizeof(long long));
printf("%d\n", sizeof(float));
printf("%d\n", sizeof(double));
printf("%d\n", sizeof(long double));
printf("%d\n", sizeof(bool));
system("pause");
return 0;
}
运行结果如下:
或许,你到现在还以为c语言里没有bool类型,其实,c99已经引入了,只是使用的时候你需要加头文件而已。
同样的代码,拿到linux的gcc下试试,看看运行结果吧。
只有long double的大小不同,其他的应该都一样。要是在g++下还会有不同,你可以试试。
指针类型的大小,32位系统下都是4.结构体的大小,前边那篇文章中已经有讲过。
(一)整形数
1.整形数的类型有:int,signed int,unsigned int(size_t),short,long,long long等等。
2.整形提升:
c语言中的数据类型转换分成两种 ,一种是隐式类型转换,一种是显式类型转换(强制类型转换)。强制类型转换
我们见的比较多了(比如动态内存分配函数里....),这里就只给出隐式类型转换。
当不同的数据类型的数进行计算时,就会发生隐式类型转化,隐式类型转换的步骤:(1)表达式中的char,short都
变成int,float变成double。(2)根据参与计算的数据类型从低精度向高精度转换。
精度低到高:char,short -> int -> unsigned int -> long ->double
float->double
下边给出几个实例:
实例1:
int a = INT_MAX;
int b = 2;
long long c = a + b;
long long c = (long long)(a + b);
long long c = (long long)a + b;
分析上边的表达式。
long long c = a + b;//发生溢出。首先计算的是a+b,都是int,已经发生溢出,再转换,当然是没用啦~~
long long c = (long long)(a + b);//原因类似上边,已经发生了溢出,才进行 转换。
long long c = (long long)a + b;//正确,b被隐含转换成long long
实例2:下边代码的运行结果是什么??
int main()
{
unsigned char a = 200;
unsigned char b = 100;
unsigned char c = 0;
c = a + b;
printf("%d %d",a+b,c);
system("pause");
return 0;
}
怎么感觉输出结果是300 300呢??其实并不是。我来分析一下。由于a和b都是无符号 char型,进行运算都会发生整
形提升。都被提升为int。所以执行c = a + b时,
a被提升为:00000000 00000000 00000000 11001000
b被提升为:00000000 00000000 00000000 01100100
a+b: 00000000 00000000 00000001 00101100
由于c是一个字节,所以a+b会被截断,变成00101100,即10进制的44
而直接输出a+b的值时,32个比特位,结果是300.
实例3:
int main()
{
char c;
unsigned char uc;
unsigned short us;
c = 128;
uc = 128;
us = c + uc;
printf("0x%x ",us);
us = (unsigned char)c + uc;
printf("0x%x ", us);
us = c + (char)uc;
printf("0x%x ", us);
system("pause");
return 0;
}
这道题看起来好像比较头疼。不过,没关系,干程序员这一行,需要的是细心,耐心,哈哈 。
c = 128.由于它是有符号数,所以8个比特位中1位是符号位,7位是实际的数.128就是10000000。然而,它的第一位
表示符号。进行整形提升时,被提升为 11111111 11111111 11111111 10000000.
uc = 128.由于它是无符号数,所有的比特位都表示实际数字。128是10000000,进行整形提升时,被提升为:
00000000 00000000 00000000 10000000
两个进行相加,取后边的16个比特位,结果是0,也是16进制的0.
当c被强制转化成无符号整形时,128的二进制中的首位1并不表示符号,进行整形提升时,被提升为:
00000000 00000000 00000000 10000000
再与uc相加,1取低位的16个比特位,结果是256,即就是16进制0x100
当uc被强制转化成有符号char时,128的二进制中的首位1表示符号,进行整形提升时,被提升为:
11111111 11111111 11111111 10000000
与c相加之后,取低位的16个比特位,结果是0xff00.
所以程序的输出结果是:0x0 0x100 0xff00
3.上边代码出现了INT_MAX,下边就此问题展开说明。
在《c语言点滴》(赵岩著)这本书中3.10节关于整形数和浮点数给出一个口诀:296两宏两头。29表示整形数的上
限是2*10^9,6表示浮点数的有效位是6位,两宏指的是_MAX类型宏 和EFLT_PSILON类型宏 ,两头指的是float.h和
limits.h。
关于这两个头文件:
float.h中主要给出浮点数,double数的最小值,最大值,等等。下边给出部分。
limits.h中给出整形数的范围,可以自行查看。
下边给出整形数这块的重点例题:
例1:
unsigned char c = -1;
printf("%u",c);
%u是无符号整形的形式。unsigned c = -1,在计算机中以补码形式存储,即为1111 1111,计算机会认为它是一个正
数当它变成无符号整形时,前边补24个0,最终就是255.
无符号char是一个字节(32位系统)。
例2:
char c = -128;
printf("%u",c);
最终的结果是,c = 11111111 11111111 11111111 10000000
-128:原码;1 1000 0000反码:1 0111 1111 补码:1 1000 0000
计算机会认为c是一个有符号的字符型,变成无符号数整形时,前边补24个1.
总结:如果是无符号数,小范围->大范围:前边补0
如果是有符号数,小范围->大范围,前边补符号位。
例3:
int i = -20;
unsigned int j = 10;
printf("%d",i + j);
程序的运行结果是-10,请看分析过程:
-20原码:10000000 00000000 00000000 00010100
反码:11111111 11111111 11111111 11101011
补码:11111111 11111111 11111111 11101100
10原码:00000000 00000000 00000000 00001010
反码:01111111 11111111 11111111 11110101
补码:01111111 11111111 11111111 11110110
两个补码相加之后转换成原码:10000000 00000000 00000000 00001010 就是-10
例4:
char a[1000];
int i = 0;
for(i = 0;i < 1000;i++)
{
a[i] = -1 - i;
}
printf("%d",strlen(a));
看看上边这段代码执行后的结果是什么。strlen可以求字符数组的长度,找\0,找到为止。
所以,i = 0时,a[0] = -1,a[i]就是-1,-2,......,-128,下来就是127,....,1,0(相当于是上边的椭圆逆时针转一
圈,0就是结尾符了,\0的ascii是0)。所以,strlen (a) = 128+127 = 255.
(二)浮点数
在IEEE754标准中,给出了V = (-1)^s*M*2^E(1<=M<2)
s代表符号,M是尾数,E是阶码。E = e+偏移位。
32位浮点数和64位浮点数的标准格式,如下图 :
知道这些之后,我们就应该推导一下浮点数的表示范围。下图以32位浮点数为例(64位的可以自己整理)
下边看一道例题:
int num = 9;
float *pfloat = (float *)#
printf("%d ",num);
printf("%f ",*pfloat);
*pfloat = 9.0;
printf("%d ",num);
printf("%f ",*pfloat);
分析:第一个printf输出9毫无疑问。第二个printf,pfloat是指向浮点数的指针。所以系统便认为9(0 00000000 00000000000000000001001)是
一个浮点数。阶码E = 0,所以该数是无限接近于0的数,所以输出0.
第三个printf,*pfloat在内存中表示为:0 10000010 00100000000000000000000,若以%d输出,就是一个比
较大的数。即就是01000001000100000000000000000000表示的整形。
第四个printf,输出9.0。也没什么问题。
关于数字,就整理这么多,如果有不合理的地方,希望指出~