C语音32个关键字
分类
C语音关键字一共32个,可以分成四类。
数据类型:12个
控制语句:12个
存储类型:4个
其他关键字:4个
数据类型关键字
char:声明变量或者函数。占一个字节(八位)。分为有符号和无符号两种,有符号范围是 -128 ~127(-2 ^7 ---- 2 ^7-1)。无符号的范围是0 ~ 255(0----2 ^8-1)。
double:声明双精度变量或者函数。双精度浮点数。16 位编译器下,double 占 8 个字节(64位);32 位编译器下,double 占 8 个字节(64位);64 位编译器下,double 占 8 个字节(64位)。 1bit(符号位) 11bits(指数位) 52bits(尾数位)。double的范围为-2 ^1024 ~ 2 ^1024(-1.79E+308 ~ +1.79E+308)。默认保留15位小数。
float:声明浮点型变量或函数。单精度浮点数。占四个字节(32位)。1bit(符号位) 8bits(指数位) 23bits(尾数位)。 float的范围为-2 ^ 128 ~ +2^128(-3.40E+38 ~ +3.40E+38)。默认保留6位小数。
int:声明整型变量或函数。数据类型占内存的位数与操作系统的位数以及编译器有关,16位系统中,keil只占两个字节(16位)。但是这种情况一般不会出现。现在基本使用没有16位系统。在keil编译器中int 类型无论在 32 位或 64 位系统中都是 4 个字节(32位)。分为有符号和无符号两种,有符号范围是 -2147483648 ~ 2147483647 (-2 ^ -31 ---------- 2 ^ 31-1) ,无符号的范围是 0 ~ 4,294,967,295(0 ---- 2 ^32)。
short:声明短整型变量或函数。short 一般占两个字节(16位)。分为有符号和无符号两种,有符号范围是 -32,768~32,767(-2 ^15 ---- 2 ^15-1),无符号的范围是 0 ~ 65,535(0 ---- 2 ^16-1)。
long:声明长整型变量或函数。分为有符号和无符号两种。long在64位系统中,占8字节(64字节)。有符号范围是 (-2 ^ 63 — 2^63-1),无符号的范围是 (0 ---- 2 ^64)。在16位和32位占四个字节(32位)。有符号范围是 -2147483648 ~ 2147483647 (-2 ^ -31 ---------- 2 ^ 31-1) ,无符号的范围是 0 ~ 4,294,967,295(0 ---- 2 ^32)。
unsigned:声明无符号类型变量或函数。整型的每一种都有无符号( unsigned )和有符号( signed )两种类型( float 和 double 总是带符号的) 。在默认情况下声明的整型变量都是有符号的类型( char默认是无符号的)。如果需声明无符号类型的话就需要在类型前加上 unsigned 。
为什么char默认无符号,其他整型默认有符号?
其他整型默认为有符号是因为在计算机中,数的表示方式有两种:有符号和无符号。有符号整数可以表示正、负数和零,而无符号整数只能表示非负数(即正数和零)。对于其他整型,默认为有符号是因为在实际应用中,有符号整数更常见且更易于理解和处理。
而char类型默认为无符号是因为在C语言的char类型既可以表示字符也可以表示整数。为了保持兼容性,char类型被默认定义为无符号,以确保字符的值始终是非负的。这样做的好处是可以直接将char类型的值与ASCII码相对应,方便进行字符处理。
注意:C++标准并没有规定char类型的默认符号性质,具体实现可能会有所不同。因此,在编写代码时,最好明确指定char类型的符号性质,以避免潜在的问题。
signed:声明有符号类型变量或函数。signed 是默认的,被修饰的这个变量是有符号的,可以存储整数和负数。
struct:声明结构体变量或函数 。在C语言中,可以使用结构体( Struct )来存放一组不同类型的数据。对齐方式是按结构体中最大类型的字节数对齐。所以有时候成员换一下位置,结构体大小就改变了。
union:声明共用体(联合)数据类型。C语言中的 union 是联合体,就是一个多个变量的结构同时使用一块内存区域,区域的取值大小为该结构中长度最大的变量的值。修改其中一个共用体变量的值,其他的也会被改变,因为它们所用的空间是一样的。
void:声明函数无返回值或无参数,声明无类型指针。void 被翻译为无类型,相应的 void * 为无类型指针。
enum:声明枚举类型。枚举定义了一些符号,这些符号的本质就是int类型的常量,每个符号和一个常量绑定。这个符号就表示一个自定义的一个识别码,编译器对枚举的认知就是符号常量所绑定的那个int类型的数字。默认从0开始依次增加。如果用户自己给首成员定义了一个值,则从那个值开始往后依次增加。或者用户不按顺序赋值也可以。
控制语句关键字
1、循环语句类型关键字
for:一种循环语句。主要用来控制循环语句的执行 。
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <math.h>
typedef unsigned char u8;
typedef unsigned short u16;
typedef unsigned int u32;
int main(void)
{
u16 i=0,sum=0; //养成编程好习惯,局部非静态变量初始化赋值。赋值随机值容易出bug
for(i=0;i<100;i++) //(循环变量赋初值;循环条件;循环变量增值)
{
sum+=i; //循环体
}
printf("sum=%hu\r\n",sum);
}
注意:for(;;) for(;一直为真;)//是死循环
do:循环语句的循环体。C语言中 do 是执行某代码块的意思,do 关键字不能单独使用,通常用在 do…while循环中。do…while 循环是在循环的尾部检查它的条件,do…while 循环与 while 循环类似,但是 do…while 循环不管真假都至少执行一次循环。
int main(void)
{
do
{
//循环体
}
while(条件表达式); //先执行一次再判断条件,真继续循环,假往下走。
}
注意:while()的 英文分号 必须要加,不加会报错。
while:循环语句的循环条件,while 语句创建了一个循环,重复执行直到条件表达式为假。while 语句是一种入口条件循环,也就是说,在执行多次循环之前已决定是否执行循环。因此,循环有可能不被执行。也就是说可以执行0次到无数次。循环体可以是简单语句,也可以是复合语句。
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <math.h>
typedef unsigned char u8;
typedef unsigned short u16;
typedef unsigned int u32;
int main(void)
{
u8 a=2,b=2;
u16 i=0,sum=0;
while(0) //不满足条件,循环体执行0次
{
sum = 10;
printf("sum=%hu\r\n",sum);
}
while(a==b) //满足条件后改变条件后不满足,循环体执行1次
{
a=5;
sum = 20;
printf("sum=%hu\r\n",sum);
}
while(1) //死循环
{
sum = 30;
printf("sum=%hu\r\n",sum);
}
while(0); //条件不成立,往下走 括号里面不是循环体
{
sum = 10; //执行
printf("sum=%hu\r\n",sum);
}
while(a==b); //条件成立,卡死,不会在往下走,括号里面不是循环体
{
a=5;
sum = 20;
printf("sum=%hu\r\n",sum);
}
while(1); //条件成立,卡死,不会在往下走,括号里面不是循环体
{
sum = 30;
printf("sum=%hu\r\n",sum);
}
}
注意:while 不带分号时while 与后面大括号内的循环体构成一个整体。满足条件才会执行{ }内容。不满足直接跳过。当while后紧跟分号时,while这一行自成一个空循环,{} 里面的代码不是循环体,一般用于卡程序不让它结束或者等待状态改变。满足条件时卡死在while,不满足条件往下走,括号里面的代码执行一次往下走。
break:跳出当前循环。break用于跳出一个循环体。多个嵌套时,只能跳出当前循环。如果想结束多层嵌套循环,直接在最外层循环加break,就能跳出全部循环。break可以跳出当前任何循环,包括死循环。
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <math.h>
typedef unsigned char u8;
typedef unsigned short u16;
typedef unsigned int u32;
int main(void)
{
u8 a=2,b=2;
u16 i=0,j=0,sum=0;
while(1)
{
sum = 30;
printf("sum=%hu\r\n",sum);
break; //跳出while死循环往下执行
}
for(i=0;i<10;i++)
{
//如果这里加break,直接跳出所有循环
for(j=0;j<10;j++)
{
break; //只能跳出j循环,循环会继续。
printf("j:i=%d,j=%d\r\n",i,j);
}
printf("i:i=%d,j=%d\r\n",i,j);
}
printf("i=%d,j=%d\r\n",i,j);
}
while(1)
{
//这里加break,直接跳出所有循环
switch(Num)
{
case 1: break;
case 2: break;
case 3: break;
case 4: break;
default:break; //跳出Switch,没有跳出while
}
}
continue:跳过本次循环,开始下一次循环。continue 语句只结束本次循环,而不终止整个循环的执行。如果条件一直成立,则会一直循环。而 break 语句则是结束整个循环过程,不再判断执行循环的条件是否成立。
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <math.h>
typedef unsigned char u8;
typedef unsigned short u16;
typedef unsigned int u32;
int main(void)
{
u8 a=2,b=2;
u16 i=0,j=0,sum=0;
while(1)
{
continue; //不会执行后面的语句但是不会跳出while循环
sum = 30;
printf("sum=%hu\r\n",sum);
}
for(i=0;i<10;i++)
{
for(j=0;j<10;j++)
{
continue;//不会执行后面的语句但是不会跳出j循环,j++会执行,条件依然判断。
printf("j:i=%d,j=%d\r\n",i,j);
}
printf("i:i=%d,j=%d\r\n",i,j);
}
printf("i=%d,j=%d\r\n",i,j);
}
2、条件语句类型关键字
if:条件语句。if (表达式) {语句;}。表达式成立(为真),则语句执行,若表达式不成立(为假),则语句不执行。
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <math.h>
typedef unsigned char u8;
typedef unsigned short u16;
typedef unsigned int u32;
int main(void)
{
u8 a=2,b=2;
u16 i=0,j=0,sum=0;
if(0) //表达式为假,不执行
{
sum = 30;
printf("sum=%hu\r\n",sum);
}
if(1)//表达式为真,不执行
{
sum = 60;
printf("sum=%hu\r\n",sum);
}
}
else:条件语句否定分支 ,与if 连用,不能单独使用。if (表达式) {语句;} else {语句;} 在C语言中 else 是与 if 一起使用的一个关键字,表示如果满足if条件则不执行 else ,否则执行else 。if 不执行,则else一定执行。if执行,则else 一定不执行。两者互斥。
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <math.h>
typedef unsigned char u8;
typedef unsigned short u16;
typedef unsigned int u32;
int main(void)
{
u8 a=2,b=2;
u16 i=0,j=0,sum=0;
if(0) //表达式为假,不执行
{
sum = 30;
printf("sum=%hu\r\n",sum);
}
else //if 不执行,则else一定执行。if执行,则else 一定不执行。两者互斥
{
sum = 60;
printf("sum=%hu\r\n",sum);
}
}
goto:无条件跳转语句。goto 语句可以使程序在没有任何条件的情况下跳转到指定的位置,所以 goto 语句又被称为是无条件跳转语句。使用 goto 语句只能 goto 到同一函数内,而不能从一个函数里 goto 到另外一个函数里。goto在同一函数里面可以随便跳转,可以跳出死循环,可以跳出多层嵌套循环。
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <math.h>
typedef unsigned char u8;
typedef unsigned short u16;
typedef unsigned int u32;
int main(void)
{
u8 a=2,b=2;
u16 i=0,j=0,k=0,sum=0;
Start:
printf("start\r\n");
for(i=0;i<10;i++)
{
for(j=0;j<10;j++)
{
for(k=0;k<10;k++)
{
printf("i=%d,j=%d\r\n",i,j);
goto while1; //直接跳出三层循环去到goto位置
}
}
}
while1:
while(1)
{
printf("while\r\n");
goto Stop; //直接跳出死循环去到goto位置
}
Stop:
printf("stop\r\n");
}
3、开关语句类型关键字
switch:开关语句。switch 语句也是一种分支语句,常常用于多分支、多种状态的情况。也就是常说的状态机。必须与case一起使用。
case:开关语句分支。case 常量表达式只是起语句标号作用,并不是该处进行条件判断。在执行 switch 语句时,根据 switch 的表达式,找到与之匹配的 case 语句,就从此 case 子句执行下去,不在进行判断,直到碰到 break 或函数结束为止。必须与switch 一起使用。
default:开关语句中的“其他”分支。default 的作用就是switch语句里所有的 case 都不成立时所要执行的语句。default 关键字用来标记switch语句中的默认分支。必须与switch一起使用。
int main(void)
{
u8 a=7,b=2;
u16 i=0,j=0,k=0,sum=0;
switch(a)
{
case 1: printf("1\r\n");break; //执行语句多时每个分支可以加{},看起来更清晰
case 2: printf("2\r\n");break;
case 3: printf("3\r\n");break;
case 4: printf("4\r\n");break;
default:printf("D\r\n");break;
}
}
4、返回语句关键字
return:终止该函数。并返回一个指定的值。可以是任何类型的数据,可以是变量,也可以是表达式。当函数执行return后,函数体将被赋值为函数的返回值,由 return 后面的参数指定。
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <math.h>
typedef unsigned char u8;
typedef unsigned short u16;
typedef unsigned int u32;
int Ret(void)
{
u8 a=7,b=2;
return a+b; //结束函数并返回表达式
printf("Ret\r\n");//上面函数已经结束,不会在执行该语句
}
int main(void)
{
int ret=0;
u16 i=0,j=0,k=0,sum=0;
switch(3)
{
case 1: printf("1\r\n");break;
case 2: printf("2\r\n");break;
case 3: printf("3\r\n");break;
case 4: printf("4\r\n");break;
default:printf("D\r\n");break; //跳出Switch,没有跳出while
}
ret = Ret();
printf("ret=%d\r\n",ret);
}
存储类型关键字
auto:声明自动变量。auto的原理就是根据后面的值,来推测前面的类型 。可以简化变量的初始化。
auto 声明的变量尽量初始化赋值,不然可能没办法判断变量是什么类型。
auto 不能直接声明数组。
auto是一个占位符,并不是一个他自己的类型,因此不能用于类型转换或其他一些操作,如sizeof会报错。
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <math.h>
typedef unsigned char u8;
typedef unsigned short u16;
typedef unsigned int u32;
auto buff[10]={1,2,3}; //不能直接定义数组
int main(void)
{
auto b = 5;
auto a;
auto* p;
printf("sizeof(auto)=%d\r\n",sizeof(auto)); //auto不是数据类型,不能进行sizeof
printf("a=%d\r\n",a); //默认int型,不赋值随机值
printf("p=%d\r\n",p); //没有指向型地址,野指针随机乱指,会出错
printf("*p=%d\r\n",*p); //没有指向型地址,野指针随机乱指,值也是随机变化
p = &b; //指向变量b的地址
printf("p-&b=%d\r\n",*p); //取变量b的值
}
extern:用在变量或函数的声明前,用来说明“此变量/函数是在别处定义的,要在此处引用。
对于变量:a.c文件中定义的变量如果需要去b.c文件中使用有两种方式:
1.在a.h中: extern 变量;然后在b.c中包含a.h即可使用。
2.直接在b.c中: extern 变量;即可使用。
对于函数: a.c文件中定义的函数需要去b.c文件中调用也有两种方式:
1.在a.h 中 :函数名;在b.c中包含a.h即可使用。
2.直接b.c中: extern 函数名;即可使用。
/*******************a.h**************/
#inlcude "b.h" //可以把b.h放到a.h中,a.c只用包含a.h就可以。也可以直接把b.h放入a.c中
/*******************a.c**************/
#include "a.h"
#include "b.h" //可以把b.h放到a.h中,a.c只用包含a.h就可以。也可以直接把b.h放入a.c中
法2:extern u8 flag; //直接在a.c中 extern 变量也可以使用b.c中的变量
法2:extern void fun(void); //直接在a.c中 extern 函数也可以使用b.c中的函数
int main(void)
{
fun();
}
/***********************b.h*************************/
法1:extern u8 flag; //在b.h中extern 变量;在a.c中包含b.h。a.c就可使用该变量;
法1:void fun(void); //在b.h中声明函数;在a.c中包含b.h。a.c就可使用该函数;
/***********************b.c*************************/
#include "b.h"
u8 flag;
void fun(void)
{
}
register:用 register 声明的变量是寄存器变量,是存放在CPU的寄存器里的,让该变量的访问速度达到最快。平时声明的变量是存放在内存中的。虽说内存的速度已经很快了,不过跟寄存器比起来还是差得远。这有效地提高了效率。
CPU操作的每一个操作结果,都由寄存器来暂时保存,最后才写入内存或从内存中读出。也就是说,变量的值通常保存在内存中,CPU对变量进行读取是先将变量的值从内存中读取到寄存器中,再进行运算,运算完后将结果写回内存中。
C语言允许使用寄存器保存变量的值,很明显这样能大大提高程序的执行速度。但是,寄存器的个数是十分有限的,我们不可能将全部的变量都声明为寄存器变量,因为其他代码也需要使用寄存器,同样,我们声明的寄存器变量也不一定直接保存在寄存器中,因为寄存器可能全部都被其他代码占用。编译器只能尽量把变量安排在寄存器中。
所以在使用寄存器变量时,请注意:
(1)待声明为寄存器变量的类型应该是CPU寄存器所能接受的类型,寄存器变量是单个变量,变量长度应该小于等于寄存器长度。
(2)不能对寄存器变量使用取地址符“&”,因为该变量没有内存地址。
(3)尽量在大量、频繁操作时使用寄存器变量,且声明的变量个数应该尽量少。
static:static 不仅可以用来修饰变量,还可以用来修饰函数。在使用 static 关键字修饰变量时,我们称此变量为静态变量。静态变量的存储方式与全局变量一样,都是静态存储方式。
修饰变量时:
1.局部变量:被static修饰的局部变量其作用时间发生改变,生命周期变长。跟全局变量有点像。存储从栈区变为静态区,默认初始值为0,且该函数结束后,变量不会被回收,仍然存在。只有主函数结束时才回收。且多次调用该函数,变量也只初始化一次。不像未被修饰的局部变量每次调用函数都会回收再分配,每次都重新初始化。
2.全局变量:被static修饰的全局变量其作用域发生改变,作用范围变小。只能在本文件中使用,不能在通过外部声明去其他文件中使用。所以其他文件里面可以出现相同的变量名。被static修饰的全局变量不需要担心在其他文件里面是否有变量重名。对于其他文件,被修饰的全局变量已经自动隐藏。
修饰函数:被static修饰的函数其作用域发生改变,作用范围变小。只能在本文件中使用,不能在通过外部声明去其他文件中调用该函数。所以在其他文件中可以出现同函数名的函数。被static修饰的函数不需要担心在其他文件是否重名。对于其他文件里面,被修饰的函数已经自动隐藏。
#include "main.h"
static u8 b; //被修饰的全局变量不能去其他文件中使用,其他文件里面可以定义相同名的全局变量
int main(void)
{
return 0;
}
static void fun(void) //被修饰的函数不能去其他文件里面使用,其他文件里面可以定义相同名的函数名
{
static u8 a; //修饰后默认值为0
u8 b = 0; //未修饰不赋值是随机值
}
其他关键字
const:const修饰变量、指针、参数、返回值等,被修饰后变为只读。即一旦赋初值就不能被修改。保护被修饰的内容,防止意外修改,增强程序的健壮性。可以看成常量。const修饰时,一定要赋值,不然后面没办法在赋值了。编译器不为只读变量分配内存,这使得它的效率也很高。
1、修饰变量
u8 const a = 2;
const u8 a = 2; //两种写法是一样的,都是把a变为只读,不能修改其值。
2、修饰指针
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <math.h>
typedef unsigned char u8;
typedef unsigned short u16;
typedef unsigned int u32;
int main(void)
{
int a = 3,b = 4,c = 5,d = 6,e = 2;
const int *p1 = &a; //修饰指针指向的内容,即指向的内容不能改变,但是指向的方向可以改变
int* const p2 = &a; //修饰指针的指向,即指向的内容可以改变,但是指向的方向不能改变
int const *p3 = &a; //修饰指针指向的内容,即指向的内容不能改变,但是指向的方向可以改变
const int* const p4 =&a; //修饰指针指向的内容和指向,即指向的内容不能改变,指向的方向不能改变
const int const *p5 =&a; //修饰指针指向的内容,即指向的内容不能改变,但是指向的方向可以改变
p1 = &b;
printf("*p1 = %d\r\n",*p1);
*p1 = 8; //报错
printf("*p1 = %d\r\n",*p1);
p2 = &c; //报错
printf("*p2 = %d\r\n",*p2);
*p2 = 9;
printf("*p2 = %d\r\n",*p2);
p3 = &d;
printf("*p3 = %d\r\n",*p3);
*p3 = 10; //报错
printf("*p3 = %d\r\n",*p3);
p4 = &e; //报错
printf("*p4 = %d\r\n",*p4);
*p4 = 11;//报错
printf("*p4 = %d\r\n",*p4);
p5 = &e;
printf("*p4 = %d\r\n",*p5);
*p5 = 11; //报错
printf("*p4 = %d\r\n",*p5);
}
总结:只要const 后面不是紧跟指针名(P),其指针指向性就能改变。只要 *号没有被修饰,也就是const在 *号后面,其指针指向的内容就能改变。
3、修饰参数
当需要把一个内容的地址复制到其他一个或多个地址时,且需要经常用到该功能,封装成函数是最方便的。但是又怕操作过程中把源地址内容改了,所有在传参时候可以把源地址用const修饰变为只读就不怕被修改。
void CopyFunction(char *Dest, const char *Srce); //把源地址的内容复制到目标地址
4、修饰返回值
如果给以“指针传递”方式的函数返回值加const 修饰,那么函数返回值(即指针)的内容不能被修改,该返回值只能被赋给加const 修饰的同类型指针。在值传递的过程种,将返回值的属性指定为const是没有任何意义的。只有在返回值是指针类型的时候,才会用到const。
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <math.h>
typedef unsigned char u8;
typedef unsigned short u16;
typedef unsigned int u32;
const int *fun(void)
{
u8 i =0;
int buff[5]={0};
const int *p = buff;
for(i=0;i<5;i++)
{
buff[i] = i;
}
return buff; //直接返回buff,会出现问题
return p; //直接返回buff,会出现问题,需要一个同类型指针指向地址后再返回
}
int main(void)
{
u8 i =0;
int *p1 = NULL;
const int *p2 = &i;
p1 = fun(); //不用const修饰的指针虽然报警告,但是可以正常接收
p2 = fun(); //可以改变指针方向不能改变内容
const int *p3 = fun(); //相同类型接收
p1[2] = 5; //把buff[2]的值改变了。所以接收返回值需要使用相同类型接收,不然容易出问题
p2[2] = 5; //报错,不能改变其内容
for(i=0;i<5;i++)
{
printf("p1[%d]=%d\r\n",i,p1[i]);
printf("p2[%d]=%d\r\n",i,p2[i]);
printf("p3[%d]=%d\r\n",i,p3[i]);
}
printf("HHH\r\n");
}
sizeof:sizeof 的作用就是返回一个对象或者类型所占的内存字节数。后面跟一对括号,但它不是函数而是关键字
ret = sizeof(char); //返回其所占字节大小
ret = sizeof(int); //返回其所占字节大小
ret = sizeof(结构体); //返回其所占字节大小
typedef:在C语言中,除系统定义的标准类型和用户自定义的结构体、共用体等类型之外,还可以使用类型说明语句 typedef 定义新的类型来代替已有的类型。 意思是给一个已经存在的数据类型取一个别名,而不是定义新的数据类型。
我们平时用的u8,u16,u32等都是给现有类型取的别名而已不是新的类型。
typedef unsigned char u8;
typedef unsigned short u16;
typedef unsigned int u32;
typedef struct
{
u8 a;
u16 b;
u32 c;
u8 *p;
}DefName; //该结构体新名字,可以去定义结构体使用
DefName DefStruct1,DefStruct2;
typedef enum{
INIT_DATA_TRAN_BY_TRAN, //不赋值默认从0开始,赋值后面的就依次加1
WAIT_ANCHOR_DATA_MSG,
SEND_COMMAND_TO_DATA_TRAN,
CHECK_ANCHOR_AND_TAG_MODE,
ENSURE_ANCHOR_AND_TAG_IN_TRAN_MODE,
TRAN_SEND_MSG,
TRAN_SEND_UART_MSG,
TRAN_WAIT_TAG_MSG,
SEND_COMMAND_TAG_TO_LOCATE_MODE,
LISTEN_TAG_MSG,
ENSURE_TAG_IN_LOCATE_MODE,
SEND_COMMAND_ANCHOR_TO_LOCATE_MODE,
LISTEN_ANCHOR_RESP,
ENSURE_ANCHOR_IN_LOCATE_MODE,
}TRAN_DATA_BY_TRAN_TRAN_STEP; //可以直接使用也可以定义更多该枚举
TRAN_DATA_BY_TRAN_TRAN_STEP DefEnum1,DefEnum2;
volatile:被修饰的内容会防止编译器优化。一般修饰经常变化和使用的变量。如果在很多地方都改变,那读取的变量的值可能是在寄存器的值(寄存器没有更新最新值),而不是变化后最新的值。被volatile修饰后,可以确保每次都能读到最新的值。
当读取一个变量时候,为了提高读取速度,编译器进行优化时会先把变量读取到一个寄存器中,以后,当再次读取变量时,就直接从寄存器中读取,当变量值在本线程里改变时,会同时把变量的新值copy到寄存器中,以保持一致,当变量因别的线程发生改变,寄存器的值可能没有及时改变,从而造成应用程序读取的值和实际的变量值不一致,当寄存器因为别的线程改变了值,原来的变量可能不会改变,也会造成应用程序读取的值和实际的变量值不一致
int a =23,b = 25;
int Value1 = 0;
volatile int Value2 = 0;
void fun1(void)
{
Value1 = (a+b)*a;
Value2 = (a+b)*a;
}
void fun2(void)
{
Value1 = (a+b)*b;
Value2 = (a+b)*b;
}
void fun3(void)
{
Value1 = (a+b)*a*b;
Value2 = (a+b)*a*b;
}
int main(void)
{
while(1)
{
fun1();
fun2();
fun3();
printf("Value1=%d\r\n",Value1);//每次提取的值不一定是最新的值,可能是上次或上几次在寄存器没有更新的值
printf("Value2=%d\r\n",Value2); //保证每次都是最新的值
}
}