目录
const的用法
const修饰的常变量不可变
int main()
{
const int num = 10;
num = 20;
printf("%d\n",num);
}
如果像上面这样修改变量,编译器会报错
可以通过以下方法修改变量:通过地址找到num
int main()
{
const int num = 10;
int* p = #
*p = 20;
printf("%d\n", num);
}
得到结果num=20,但破坏了const的语法规则
const可以修饰指针
int main()
{
const int num = 10;
const int* p = #
*p = 20;
printf("%d\n", num);
}
如上,const修饰*p指针后,该代码会报错,那p变量本身可不可以改呢?答案是可以的
得出结论,const放在*的左边(const int* p和int const *p)const修饰的是*p,表示p指向的对象不能通过p来改变,但是p变量中的地址是可以改变的
接下来对该代码进行一些改变
得出结论,const放在*的右边(int* const p)const修饰的是p,表示p的内容不能被改变,但是p指向的对象是可以通过p来改变的
数据类型
如果是有符号的数据,最高位是符号位,最高位是0表示正数
无符号数用%u(4byte)打印,%u会把补码当成原码直接打印
short(2byte - 16bit) 默认为有符号的(int、long也默认为有符号的)
unsigned short 无符号的short
char 是有/无符号? 不确定,取决于编译器的实现
假设有符号(1byte - 8bit) 可表示范围 -128~127
00000000 -> 0
01111111 -> 127
10000000 -> 直接解析为 -128
11111111 -> 反11111110 -> 原10000001 -> -1
构造类型(自定义类型):
- 数组类型
- 结构体类型 struct
- 枚举类型 enum
- 联合类型 union
整形在内存中的存储
- 原码
直接将数值按照正负数的形式翻译成二进制就可以
- 反码
将原码的符号位不变,其他位依次按位取反就可以得到了
- 补码
反码+1就得到补码
正数的原、反、补码都相同
三种表示方法均有符号位和数值位两部分
整形数据存放内存中其实存放的是补码(CPU中只有加法器)
大端字节序存储:把一个数据低位字节处的数据存放在高地址处,把高位字节处的数据存放在低地址处
小端字节序存储:把一个数据低位字节处的数据存放在低地址处,把高位字节处的数据存放在高地址处,例(vs编译器):
设计一个小程序来判断当前机器的字节序:
#include<stdio.h>
int main()
{
int a = 1;
char* p = (char*)&a;
if (*p == 1)
printf("小端\n");
else
printf("大端\n");
return 0;
}
但这样是一次性的代码,可以封装成一个函数:
#include<stdio.h>
check_sys()
{
int a = 1;
char* p = (char*)&a;
if (*p == 1)
return 1;
else
return 0;
}
int main()
{
int ret = check_sys();
if (ret == 1)
printf("小端\n");
else
printf("大端\n");
}
对函数部分简化一下:
check_sys()
{
int a = 1;
return *(char*)&a;
}
整形提升:无符号数在高位补0,有符号数按符号位补高位
例1:
int main()
{
char a = -128;
printf("%u\n",a);
}
-128的原、反、补:
10000000000000000000000010000000
11111111111111111111111101111111
11111111111111111111111110000000
截断(char):10000000 -> a
(打印格式%u)整形提升(按char):11111111111111111111111110000000(无符号数)
结果为4294967168
如果是 char a = 128,则同上
例2:
unsigned char i = 0;
int main()
{
for (i = 0; i <= 255; i++)
{
printf("hello world\n");
}
}
结果是:死循环
char能存的最大数为255(11111111),再加1(100000000),发生截断(00000000),i变成0
浮点型在内存中的存储
float.h 定义了浮点数的取值范围的相关信息
limits.h 定义了整形数的取值范围的相关信息
此结果表明:整数和浮点数在内存中的存储方式是有差异的
IEEE 754规定,二进制浮点数V可以表示成下面的形式:
- (-1)^S * M * 2^E
- (-1)^S表示符号位,当S=0,V为正数;当S=1,V为负数
- M表示有效数字,大于等于1,小于2
- 2^E表示指数位
5.5 -> 10进制的浮点数 二进制:101.1
(-1)^0 * 1.001 * 2^2
S M E
对于32位的浮点数,最高1位是符号位S,接着的8位是指数E,剩下的23位为有效数字M
对于64位的浮点数,最高1位是符号位S,接着的11位是指数E,剩下的52位为有效数字M
一些特别规定:
- 计算机内部保存M时,舍去第一位1,读取的时候再加上去,这样可以节省1位有效数字。
- 对于指数E,首先,E为一个无符号整数,因为科学计数法中E可以为负,IEEE 754规定存入E的真实值必须再加上一个中间数(8位的E加127;11位的加1023。不管E为正负)。
- E为全0时,E等于1-127(或1-1023)即为真实值,M不再加第一位的1。这样做为了表示±0,以及接近于0的很小的数字;E为全1时,如果M全为0,表示±无穷大(正负取决于符号位S)。
浮点数在计算机中不能精确保存,所以不能用==判断(类似if(f==0.0)是不可以的),只能比较两个数差值是否在误差范围内