数据类型:
c语言在使用什么变量之前一定要定义,他的定义就是依据这个数据类型来实现定义。
计算机的本质是:他是一个计算的机器,假设计算机想要做 3 + 4这个运算,3 + 4:计算机是不知道这个东西是什么,3 4对于计算机来说就是数据,3 4对于计算机来说就是数据,+:运算符,告诉计算机你要干什么,数据类型的本质是告诉计算机:你要给我分配多大的内存,内存是没有什么类型的概念,整数和小数是人为去规定的,我告诉计算机这个数据是一个整数,那么这个数据就是整数。
我们可以通过基本的数据类型来实现这个操作,在c语言里面有一些定义好了的数据类型,分为整数和小数,基本的整数类型:
(signed) char/unsigned char1个字节
(signed) short/unsigned short2个字节
(signed) int/unsigned int4个字节
(signed) long/unsigned long32位机:4个字节 64位机:8个字节
(signed) long long/unsigned long long 8个字节
其中signed/unsigned:告诉计算机你接下来的数据是否有符号,如果是signed(有符号,编程时基本省略不写):那么这个数据的最高bit为符号位,0代表正数,1代表负数。
计算机存放数据的地方我们叫内存,我们内存条上面有很多个小的格子 --- bit,每个格子就是一个锁存器 --- 锁住一个状态,然后每8个bit编成一组 --- 字节 byte,因此计算机里面的最小存储单位是字节。也就是1字节=8bit。
char:8个bit,最高的bit为符号位,因此他能存放数据的地只会剩余7个因此他的取值范围:-128 ~ 127,unsigned char:8个bit 最高的bit为数据位因此他的取值范围:0 ~ 255。
我们在实现计算机的运算的时候,两个数据必须要预估大小。例如:我要实现两个人的年龄相加,这个时候我就要预估年龄的大小,就算两个是老人,一个80岁,一个90岁,80 + 90 = 170 ,而127<170<255,因此我们要用unsigned char去定义。如果用char定义的话,空间不够就爆了,导致数据存储不全。当然用unsigned short也可以,但是必然会浪费空间,导致一些bit位没有合理运用,所以合理的预估空间大小是程序员必须踏出的一步。
小数浮点型: 用来保存小数的地方,内存都是那个内存,只是规则不一样。
float:单精度4个字节,
double:双精度8个字节,
long double:长精度16个字节,
使用这个整数和小数的时候首先应该定义:
int a;
a = 1024;
char b;
b = 16;
float f;
f = 0.4;
f = 5;
构造类型:程序员根据c语言的相关规定自行的定义出来的有:数组,结构体,联合体,枚举。
C语言能活到现在还是这么NB,靠的什么?靠的指针(YYDS)。
指针类型 *
空类型:void
在c语言里面这个void只会在三个地方使用:
1 函数的返回值类型,表示没有返回值:
void func()
{
}
2 作为函数的形式参数,表示这个函数没有参数
void func(void)
{
}
3 可以在后面加 *
void * -> 万能指针,通用指针,表示什么指针都能接受。
我们研究计算机的数据存储,首先我们就应该学会怎么去使用变量,变量在使用之前都是需要定义的,变量的定义的方式只有一种:
类型 变量名;
eg:
int a;
int b;
a = 3;
b = 4;
int c = a + b;
printf("%d\n",c);
将上面的例子写入代码,编译执行,计算机保存的数据分为两种:常量,变量,常量:值不能改变的我们叫常量,a = 10;//10本身的意思就是10个,不能将他的语义给改变,因此这个10就是一个常量 -- 表示值不能更改,在计算机里面就会被存放在一个只读的存储区里面。
计算机里面的常量表示:8进制:以0开头的数据我们表示位8进制
0xxx:x的取值范围 0 ~ 7
逢8进1
8进制 二进制
0 000
1 001
2 010
3 011
4 100
5 101
6 110
7 111
10进制:
0~9中间的某一些数字组成的一个数据
开头1 ~ 9
16进制:0x/0X开头的位16进制数据
16进制 2进制
0 0000
1 0001
2 0010
3 0011
4 0100
5 0101
6 0110
7 0111
8 1000
9 1001
a/A 1010
b/B 1011
c/C 1100
d/D 1101
e/E 1110
f/F 1111
我们计算机的最小存储单位:字节 = 8bit,8 = 4 * 2;
因此一个字节就可以采用两个数的16进制表示
1110 1101 -> 0xed
101 0110 -> 0x56
111 0100 1010 1010 1010 ->0x74aaa
0x69 -> 0110 1001
字符常量:计算机是美国先搞出来的,他们弄出来是为了解决他们的社会问题的,而社会问题里面出现最多的数据就是 a b c ....
![](https://i-blog.csdnimg.cn/blog_migrate/70b71302075a9c050cfcd7a891a98363.jpeg)
ASCII码表(转载于百度)
为了寻求简单的表示方式,他们给每一个字符都编了一个编号叫ASCII码,编码的时候发现,这写字符不多,1个字节就搞定了。
在计算机里面这个ascii码和字符是一 一对应的,c语言里面用''(单引号)引起来的这个玩意儿我们就叫字符。而下面这种字符我们叫转义字符:
'\n' -> 换行
'\t' -> tab
'\r' -> 回车
linux:回车 --- 换行并新起一行 '\n'
win:回车 -- 回车并换行 '\r''\n'
我们在表示一个字符的时候可以采用下面几种形式,常用的是采用一个整数或者一个字符来表示一个字符。
char a = 'A';
char b = 65;
'\ooo':取ooo这个8进制的整数来表示字符
char a = 'A';
char b = '\101'
'\xhh':取hh这个16进制的整数来表示对应的那个字符
char a = 'A';
char b = '\101'
char c = '\x41'
补充:50000us -> 12mhz -> 12分频之后就是1mhz -> 1s振动1000000次 每次是1us -> 指令周期就是1us。
65536 - 50000 = 15536 TH0 = 0X3C TL0 = 0XB0
12M晶振每秒可产生1M个机器周期,1M个机器周期就是1000000个机器周期。一个机器周期为1us, 50ms就需要50000个机器周期,定时器在方式1工作,为16位,最大值为65536,所以需设初值为65536-50000=15536;
15536转化为16进制得3cb0;故高位TH0=0x3c;TL0=0xb0;
————————————————
版权声明:转载于博主92年程序员。
原文链接:https://blog.csdn.net/qq_39790474/article/details/85034038
浮点型常量:由整数、小数、小数点、e/E、一个可选的符号 :浮点型常量
这个浮点型常量后面可选一个后缀(可以写也可以不写,写了就是告诉别人你用的是一个浮点型,并且可以显示精度(f/F,l/L)。
floatf/F(单精度浮点型)5.4f 若5.4后面没有加f或F,则默认为double类型(双精度浮点型)。long double l/L(高精度浮点型)。
3.14e5表示3.14×10的5次方。
我们在写这个浮点型常量的时候整数和小数为0都可以省略不写,但是不能同时省略
eg:0.14e3 可以写为: .14e3,而5.0e4 可以写为:5e4。
浮点型的存储和整数的存储有很大的区别,后面我们探讨。
变量:变量是在程序的运行期间,他的值是可能会改变。
变量的值可大可小,因此我们在使用之前一定要预估他的空间,他的最大值最小值分别是多少,我开出来之后会不会越界。
如:我要表示一个人的学号,在我们班上就只有40多个人,用char类型(之前提过范围是-128~127)就可以了,当我们要放入到学校的时候就不行了,这个时候我们就需要将我们的数据的空间开大一点。我们就可以考虑使用int short。
变量的定义:类型(构造类型) 变量名;
变量名:这个命令要符合c语言的命名规则:由字母,下划线,数字组成,开头只能是字母或者下划线。
为了避免同名,程序员在取名字的时候尽量让这个名字复杂一点,
类型(构造类型) 变量名;当编译器看到这个代码之后,他马上就会通过这个类型算出你要开出来的内存大小,如:
int a;//编译器会马上给你找4个字节(连续的)
//这个a只是这个空间的名字(代号)
//后面我们用这个a的时候 编译器是最终通过这个a找到刚刚开出来的4个字节
初始化:变量定义完毕之后可以马上给值。
int a = 10;//开辟出来4个字节叫a,并且同时初始化,然后马上给这个4个字节赋值为:0x0000000a
变量在使用的时候有左右之分:
int a;
a = 10;
int b;
b = a;
a可能出现在等号的左边也有可能出现在右边:
当a在等号的左边的时候:这个时候我们叫他左值(代表一个可写的地址),这是一个写入操作
当a在等号的右边的时候:这个时候我们叫他右值(代表一个可读的地址),这是一个读出操作
常量:在程序运行期间,其值不能改变,变量:在程序运行期间,其值能改变。
数据在计算机里面的存储,整数存储:在内存里面是以二进制的补码存储的,并不是直接存储的二进制,正数在存储的时候直接以二进制存储也就是正数的补码就是他的原码。
如:4 存储形式为 0000 0100
负数和正数存储不一样,负数的补码的运算过程如下:
1· 求他的绝对值
2· 将他的绝对值的源码求出来然后取反:0变为1,1变为0。
3· 取反的结果 + 1 得到补码。
如:-4 的绝对值为 4,求出他的4的二进制:0000 0100,然后取反得:1111 1011,
3 取反的结果 + 1 -> 最终的补码
1111 1011
+ 1
------------
1111 1100
-4 在内存里面的存储就是 1111 1100
小数存储:分为三个部分double: 1(符号位) + 11(指数) + 52(底数)float:1(符号位) + 8(指数) + 23(底数)。我们存放都是以科学计数的形式存放的,以floa为例:
1011.001 写为 1.011001 * 2 ^ 3 ps:由于这里是二进制表示,等价于十进制的1.0011001*10^3
上述的这个例子:我需要存前面的符号 0表示是正的 1表示是负1bit(符号位),2的n次方我需要存放:
2本身是固定,这就不需要存储,n是可能会变动的,因此需要存储 8bit(指数),n本身是可能为负数的,因此它又有符号,为了解决这个符号问题,我们固定往这个地方 + 127将所有的负数转换成正数。
0.000001101 可写为1.101 * 2 ^ -6
因此我们存这个-6的时候就会把它变成 -6 + 127 = 121,小数本身必须要存储: 23bit(底数)
1.011001 * 2 ^ 3
1.101 * 2 ^ -6
上述的两个例子底数有一个共同点:前面都是1,既然都是1,那么这个1就可以不用保存了
1.011001底数就是 011001
1.101 底数就是101
如:
6.375 -> 110.011 -> 1.10011 * 2 ^ 2
我们需要存的 符号为0 指数为 2 + 127 = 129 底数:10011
存储为:0 10000001 10011000000000000000000
赋值问题:在整数的赋值里面,有几种情况我们需要考虑
1 长的赋值给短的
int -> char
int a = 12345678;
char b;
b = a;
这个时候直接舍弃高字节,直接丢弃不要了
int a = 0x12345678
char b;
b = a;->0x78
2 短的赋值给长的
(短的)如果是无符号的,低字节直接拷贝,高字节补0
(短的)如果是有符号的,低字节直接拷贝,高字节补符号位
char a = -3;
short b = a; -> -3
a:1111 1101
b:1111 1111 1111 1101
将其回转回去,也就是将补码形式往反方向做一遍就可以了
第一步,(先减1)-1 -> 1111 1111 1111 1100
第二步, 取反 -> 1000 0000 0000 0011
第三步,转为10进制-> -3
我们为什么要采用补码存放负数??
1 计算机的底层是没有什么符号的概念
2 你给他什么值就会以什么值取做计算,不会做任何的处理
3 减法变成加法之后,我们就可以去掉这个很难实现的减法器
最后得到的结果是正数还是负数不是有cpu决定的,是由你的代码(上下文决定的)
也就是你定义出来的变量编译器做解释的时候决定的
-3 -> cpu看它的时候实际上不是-3 是 1111 1101
char a = -3;
这个a就是带符号的规则去解释
unsigned char a = -3;
这个a就是不带符号的规则去解释
下面的这个a实际上是253
char a = -3;
printf("%d\n",a); -3
printf("%u\n",a); 2 ^ 32 - 3 -> 0xffffffff + 1 - 3 -> 0xfffffffd
1 00000000 00000000 00000000 00000000
%d: 固定看成int
%u: 固定看成uint
溢出问题:我的内存空间不能将结果保存完毕,还有一些信息丢失了丢失的就只能丢失,这个溢出的结果还是计算机的cpu算出来的,你计算出来的结果就是相当于一个长的内存,然后赋值给短的内存,前面直接丢弃,后面的直接拷贝。
unsigned char a = -3;//将-3的二进制给a
a的二进制为 1111 1101
printf("%d\n",a);//a是无符号的,因此短赋长的时候前面补0
00000000 00000000 00000000 1111 1101 -> 253是一个正数
printf("%u\n",a);//253
char a = 253;
a = 1111 1101 = -3;
char b;
b = a + 7; //= 4
printf("%d\n",b);//4
printf("%u\n",b);//4
short a = 32767;
short b = 32767 + 2;
printf("%d\n",b);//-32767
printf("%u\n",b);//2 ^ 32 - 32767
char a = 127;
char b = 3;
char c = a + b;
一定要记得:cpu是没有符号的概念的,它只管计算,最终的结果就看二进制解释成什么东西了