一、数据类型
前面介绍了基本的内置类型,如:
char //字符数据类型
short //短整型
int //整型
long //长整型
float //单精度浮点数
double //双精度浮点数
类型的意义:
1.使用这个类型开辟内存空间的大小(大小决定了使用范围)。
2. 如何看待内存空间的视角
类型的基本分类
整型家族:
1.char
unsigned char
signed char
2.short
unsigned short [int]
signed short [int]
3.int
unsigned int
signed int
4.long
unsigned long [int]
signed long [int]
浮点数家族:
1.float
2.double
构造类型
1.数组类型
2.结构体类型:struct
3.枚举类型:enum
4.联合类型:union
指针类型
例如:
int *pi;
char *pc;
flaot* pf;
void *pv;
空类型
void 表示空类型(无类型)
通常应用于函数的返回类型、函数的参数、指针类型。
二、整型在内存中的存储
1.原码、反码、补码
原码:直接将数值按照正负数的形式翻译成二进制就可以得到原码。
反码:将原码的符号位不变,其他位依次按位取反就可以得到反码。
补码:反码+1就得到补码;
例如:
int main()
{
int a = 20;
//00000000000000000000000000010100 - a的原码
//0x00000014 -16进制
//整数的原、反、补码相同
int b = -10;
//10000000000000000000000000001010 - b的原码
//11111111111111111111111111110101 - b的反码
//11111111111111111111111111110110 - b的补码
//0xffffff6
return 0;
}
对于整型来说:数据存放内存中其实存放的是补码
a在内存中的存储:
b在内存中的存储:
上面的a和b的存储方式都是倒着存储的,这就是小段(存储)模式。
2.大小端存储
大段存储(大段字节序存储):
把一个数据的低位字节的内容存放在高地址处,高位字节的内容存放在低地址处。
小端存储(小段字节序存储):
把一个数据的低位字节的内容存放在低地址处,高位字节的内容存放在高地址处。
例如:
相关练习
写一个代码判断当前机器的字节序
int check_sys()
{
int a = 1;
char* p = (char*)&a;
return *p;
}
int main()
{
int ret = check_sys();
if (ret == 1)
printf("小段\n");
else
printf("大段");
return 0;
}
三、相关例题
1.
int main()
{
char a = -1;
//10000000000000000000000000000001 - -1的原码
//11111111111111111111111111111110 - -1的反码
//11111111111111111111111111111111 - -1的补码
//a是char类型的,所以要截断存放
//11111111 - a
//最高位1是符号位,整型提升补1
//11111111111111111111111111111111 -这是补码,打印出来就是-1
signed char b = -1;
//b也同样的
unsigned char c = -1;
//c的类型是无符号的char,最高位不是符号位,整型提升要补0
//00000000000000000000000011111111 - %d打印出来就是255
printf("a=%d b=%d c=%d", a, b, c);
//%d 打印有符号的整形
return 0;
}
2.
int main()
{
char a = -128;
//10000000000000000000000010000000 - -128的原码
//11111111111111111111111101111111 - -128的反码
//11111111111111111111111110000000 - -128的补码
//10000000 - a
//整型提升- 补1
//11111111111111111111111110000000
//因为是由%u打印,最高位不是符号位,所以这个数被解析位一正数
//读出来就是4294967168
printf("%u\n", a);
//%u 打印无符号的整形
return 0;
}
3.
int main()
{
int a = -20;
//10000000000000000000000000010100 -a的原码
//11111111111111111111111111101011 -a的反码
//11111111111111111111111111101100 -a的补码
unsigned int b = 10;
//00000000000000000000000000001010 -b的原码(补码一样的)
//补码进行运算
//11111111111111111111111111110110 -补码
//10000000000000000000000000001001
//10000000000000000000000000001010 -原码 也就是-10
printf("%d\n", a + b);
return 0;
}
4.
char的取值范围:-128~127
unsigned char 的取值范围:0~255
int main()
{
char a[1000];
//由符号的char的取值范围是:-128~127
int i;
for (i = 0; i < 1000; i++)
{
a[i] = -1 - i;
}
//i=0时a[0]被赋值为-1
//i=1时a[1]被赋值为-2
//...
//a[127]被赋值为-128,-128再减1就会变为127
//127再一直减到0
//strlen的结束标志就时'\0'
//所以数一数0之前有多少个数字就得到结果了。128+127(255)
printf("%d", strlen(a));
return 0;
}
四、浮点型在内存的存储
浮点数家族有:float、double、long double
浮点数的存储规则
根据国际标准IEEE(电气和电子工程协会) 754,任意一个二进制浮点数V可以表示成下面的形式:
1.(-1)^S * M * 2^E
2.(-1)^S表示符号位,当S=0,V为正数;当S=1,V为负数。
3. M表示有效数字,大于等于1,小于2。
4. 2^E表示指数位
IEEE 754规定:
对于32位的浮点数,最高的1位是符号位s,接着的8位是指数E,剩下的23位为有效数字M。
对于64位的浮点数,最高的1位是符号位S,接着的11位是指数E,剩下的52位为有效数字M。
IEEE 754对有效数字M和指数E,还有一些特别规定。
M的规定:M只需要保留小数点后面的数字,剩下不够的位数补0。
E的规定:E是一个无符号整数,如果E为8位,它的取值范围为0~255,E如果是11位,它的取值范围为0到2047。但是科学计数法中的E可以是负数,因此我们需要加上一个中间数。对于8位的E,加上127,对于11的E,加上1023.
举个例子:
十进制的6.0,写出二进制是110.0,按照V的格式写可以得出S=0,M=1.10,E=2,
用32位二进制表示就是:0 10000001 10000000000000000000000
相关例题
int main()
{
int n = 9;
float* pFloat = (float*)&n;
printf("n的值为:%d\n", n);//9
printf("*pFloat的值为:%f\n", *pFloat);
//00000000000000000000000000001001 -9的补码
//0 00000000 00000000000000000001001 把9的补码当成浮点数拿出来解析,
// (-1)^0*0.00000000000000000001001*2^-126 用V的格式表示
//0.000000 读出来就是0.000000
*pFloat = 9.0;
//1001.0 9.0的二进制
//1.001*2^3 所以S=0,M=001,E=3
//0 10000010 00100000000000000000000 -9.0的补码
printf("num的值为:%d\n", n);//9.0的补码用%d打印就是1091567616
printf("*pFloat的值为:%f\n", *pFloat);//9.0
return 0;
}