const是C语言中的一个关键字,用来限制一个变量不允许被改变。在某个程序中使用const可以提高程序的健壮性。另外,在查看别人的代码时,清楚地了解const所起的作用,有助于理解别人的程序。01const简介下面简单介绍一下const,基本都是教科书上的知识。const修饰的变量,其值存放在只读数据段中,其值不可更改。称为只读变量。关于什么是数据段,什么是代码段,请看我之前的文章《C语言的内存分配》。常量一个;常量一个;以上两条语句都可以将a声明为整数,并且不能修改它的值。您可以选择这两种方法中的任何一种。常量可以在定义时初始化。intconst=15;当指针和常量结合起来,就变得很有趣了,因为有两种东西可以变成常量,指针和它所指向的实体。一般大家在考机考二级和大学面试的时候经常会遇到。诠释*一个;a是一个非常常见的整数指针。常量*a;此时,它是一个指向整型常量的指针。也就是说,您可以修改指针的值,但不能修改它指向的值。诠释*常量;那么a是指向整数的常量指针。这个指针是常量,它的值不能被修改,但是你可以修改它指向的整数的值。intconst*consta;这时指针本身和它指向的值都是常量,不允许修改。那么问题来了,就像C语言中运算符的优先级一样,这个东西非常难记。在实际开发中,我们直接使用()符号来解决优先级的问题。上面指针和const的组合这么麻烦,学习的目的是什么?1、合理使用关键字const,可以让编译器自然而然地保护那些不想改变的参数,防止它们被无意的代码修改。简而言之,这减少了错误。2、基于以上原因,一些优秀的开源代码会使用const这个属性。深入了解之后,方便我们阅读和理解一些优秀的开源代码。02常量的应用以上是教材中对const定义的简单介绍,下面说说const在日常开发中的应用。在单片机开发中,const定义了一个常量。在单片机开发中,定义在函数体外的一个常数是常数a=5;存储在单片机内部Flash中。不懂的请看之前的文章《C语言在STM32中的内存分配》。那么当它和上面提到的指针结合的时候,是不是也存储在了内部的Flash中呢?让我们验证intdata=0x1234;intconst*a=&data;int*constb=&data;intconst*constc=&data;intmain(void){intdata1=0x1234;一个=&数据1;数据1=*b;数据1=*c;while(1);}它们的内存分配如下b和c分配给internalflash,a分配给rammiddle。其实这也很好理解。根据上面const的定义,单片机分配时,不能修改的变量,即只读变量放在flash中,可读写的变量放在ram中。仔细想想我明白了。用作函数参数的常量,非指针参数(即传值参数)不会修改原值,const对其没有意义,所以这里只讨论参数为指针加const的情况。如上所见,指针加const有3种情况。这里先讨论intconst*a;也就是说,你可以修改指针的值,但不能修改它指向的值。intfun(int*p){if(*p==0xA5){return*p;}else{p++;返回*p;}}上面是一个简单的例子,就是传入一个指针,函数读取指针内容,执行不同的命令。类似于串口接收,一个函数在内部处理这些数据,但不能修改,串口接收到的数据可能在其他地方有用。在上面的例子中,没有问题,因为代码都“尽在掌握”。我知道写操作是不是在函数内部进行的。但是有一种更规范的写法。intfun(intconst*p){if(*p==0xA5){return*p;}else{p++;返回*p;指针指向的内容只能修改和读取。如果你试图修改它,编译器会直接报错。但是函数内部也可以绕过修改数据,如下:intfun(constint*p){int*p2=p;/*同名指针会绕过const的限制*/*p2+=1;return*p;}那么,int*consta;有没有对应的使用场景呢?在下面的接口设计中,如果函数试图修改指针的值,也就是指针指向的位置,编译器会直接报错。不过这里的例子很现实,因为即使去掉p2的const修饰,编译器也会直接报waring,因为p2是入参。这里只是举个简单的例子,意思大家都明白。日常开发中,入参为intconst*a;有很多使用场景。在C++中,C++中可以使用application和const,C++中可以使用application语法。什么是应用这里不展开。比如C++函数参数中经常加const修饰,如下:voidfind(constint&x){…}最后给出两个常用的标准C库函数声明,它们都是使用const的典范。1、字符串拷贝函数:char*strcpy(char*strDest,constchar*strSrc);2、返回字符串长度函数:intstrlen(constchar*str);03#defineandconst#defineprecompileandconstinsomecases下面有些“混淆”,如下#defineMAX_NUM5intconstmax_num=5;voidfun(){if(len>MAX_NUM)if(len>max_num)}上面的代码第5行和第6行可以工作。那么具体分析下它们的区别1.#define的数据是宏定义,占用代码段空间(对应单片机:内部闪存),const定义数据类型,占用数据段(对应单片机:内部闪存)。内部内存)。2、如上,#define是宏定义,在预编译阶段直接替换,const是数据类型。#defineMAX_NUM5intconstmax_num=5;intdata[MAX_NUM];intdata2[max_num];上面代码第四行无法通过编译,因为max_num是int数据类型变量,数组定义的长度不能使用变量。其实在本章的第一个例子中,#define更适合只判断长度,因为凡是允许字面值常量的地方都可以使用宏定义。3.define只是一个简单的字符串替换,没有进行类型检查。而const有对应的数据类型,需要进行判断,避免一些低级错误。define只是简单的字符串替换,会造成边界效应,比如定义#defineA1#defineBA+3#defineCA/B3那么c是什么?c=A/B3=A/A+33=1/1+33=10;所以在使用这个方法的时候,可以直接用括号括起来,这样就不怕边界效应了。4.const不能重新定义,两个相同的不能定义,define比较嚣张。它通过undef取消一个符号的定义,然后重新定义它。也可用于判断宏定义是否存在,常用于头文件中,防止头文件被重复引用。#ifndefGRAPHICS_H//防止graphics.h被重复引用#defineGRAPHICS_H...code...#endif5,const常量可以调试,define不能调试,主要是预编译阶段已经替换了,当调试就不管它了。本文转载自微信?《知乎编程》,可通过以下二维码关注。转载本文请联系知编程公众号。
