深入聊一下const关键字

2023-01-22 0 277

const是两个C词汇的URL,它限量发行两个表达式不容许被发生改变。采用const在很大流程上能提升流程的易用性,除此之外,在观赏自己标识符的这时候,明晰认知const拉艾的促进作用,对认知自己的流程略有协助。

1、const概要

下面单纯叙述呵呵const,基本上都是课本的科学知识。const润色的表达式,其值存放在黎贞统计数据段中,其值无法被发生改变。称作黎贞表达式。有关甚么是统计数据段,甚么是程序标识符,请看我以后的该文《C词汇的缓存分配》。

int const a; const int a;

下面四条句子都能将a新闻稿为两个有理数,它的值无法被修正。这三种形式你能任一选一类方可。

自表达式在表述时能被调用。

int const a =15;

当操作符和自表达式结合时,就会很有意思,即使有可说小东西都可能将正式成为自表达式,操作符和它对准的虚拟。通常我们在理工学院考计算机系统三级和复试时时常会碰到的。

int *a;

a是两个很通常的对准auth的操作符。

int const *a;

此时则是两个对准auth自表达式的操作符。换句话说,你能修正操作符的值,但无法修正它对准的值。

int *const a;

此时a是两个对准auth的自表达式操作符。这个操作符是自表达式,它的值无法修正,但你能修正它所对准的auth的值。

int const *const a;

这个这时候无论是操作符本身还是它所对准的值都是自表达式,都不容许修正。

那么问题来了,就像C词汇的运算符的优先级,这个小东西很不好记忆,在实际开发中,我们直接多用()符号解决优先级的问题。上面操作符和const紧密结合那么麻烦,学习为了甚么呢?

1、合理地采用URLconst能使编译器很自然地保护那些不希望被发生改变的参数,防止其被无意的标识符修正。简而言之,这样能减少bug的出现。

2、正是基于上面的原因,一些优秀的开源标识符都会利用const这个属性,深入细致认知后,方便我们阅读认知一些优秀的开源标识符。

02、自表达式的应用

上文就简述了呵呵课本中的const表述,现在说呵呵const在我日常开发中的应用。

在单片机开发中

const表述两个自表达式,在单片机开发中,两个表述在函数体外的自表达式constint a = 5; 它是存储在单片机内部Flash里的,不懂的同学请看以后的该文《C词汇在STM32中的内存重新分配》。那么上文提到和操作符紧密结合时,也是存储在内部Flash中吗?我们来验证呵呵

int data = 0x1234; int const *a = &data; int *const b= &data; int const *const c= &data; int main(void) { int data1 = 0x1234; a =&data1; data1 = *b; data1 = *c; while(1); }

它们的缓存重新分配如下

深入聊一下const关键字

b和c是重新分配到内部flash的,a是重新分配到ram中的。其实这也很好认知,根据下面的const的表述,单片机在重新分配时,将无法修正的表达式,也是黎贞表达式放到flash中,能读写的表达式放到ram中,这个我们仔细想呵呵就明白了。

自表达式作为函数的参数

非操作符参数(也是传值参数)不会被修正原始值,const对它是没有意义的,所以这里只讨论参数是操作符加const的情况。

在下面看到,操作符加const共3种情况,这里先讨论int const *a; 也是你能修正操作符的值,但无法修正它对准的值。

int fun(int *p) { if(*p == 0xA5) { return*p; }else{ p++; return *p; } }

下面是个单纯的例子,也是传入两个操作符,函数读取操作符对准的内容,执行不同的命令。类似串口接收,两个函数内部处理这些统计数据,但无法修正,可能将串口接收的统计数据在其他地方还有用。

在上述例子中,没有问题的,即使标识符全在“掌控”中。函数内部是否进行写操作,自己是知道的。但还有两个更规范的写法。

int fun(int const *p) { if(*p == 0xA5) { return *p; }else{ p++; return *p; } }

这里写法,是明显表现出自己的设计意图,函数内部无法对操作符对准的内容进行修正,只能读取。

深入聊一下const关键字

如果尝试修正,编译器会直接报错的。但函数内部也是能绕过去,修正的统计数据的,如下

int fun(const int *p) { int *p2 = p; /* 来个重名操作符会绕过const的限制*/ *p2 += 1; return*p; }

那么对于int *const a;有没有对应的采用场景呢?如下

深入聊一下const关键字

这样的接口设计,如果函数内部尝试修正操作符的值,也是操作符对准的位置,编译器就会直接报错。

不过这里例子很现实,即使即使去掉p2的const润色,编译器会直接报waring,即使p2是入参。这里只是单纯举例子,我们认知意思就好。

深入聊一下const关键字

在日常开发中,入参是intconst *a; 采用场景比较多。

C++中应用加const

C++中能采用应用的语法,这里不再展开甚么是应用,如下例子,C++函数参数中引用时也常加const润色,如下

void find(constint &x) { ……. }

最后,举两个常用的标准C库函数新闻稿,它们都是采用const的典范。

1.字符串拷贝函数:char*strcpy(char*strDest,constchar *strSrc);

2.返回字符串长度函数:intstrlen(constchar *str);

3、#define和const

#define预编译和const在某些情况下有些“混淆”,如下

#define MAX_NUM 5int const max_num = 5; void fun(){ if(len >MAX_NUM) if(len> max_num) }

上述标识符5行和6行都能起效果。那么我们就详细分析呵呵它们的区别

1、#define的统计数据是宏表述,它占用的是程序标识符空间(单片机对应:内部flash),const表述两个统计数据类型,它占用的是data段(单片机对应:内部ram)。

2、如上,#define是宏表述,在预编译阶段直接替换,而const是统计数据类型。

#define MAX_NUM 5 int const max_num = 5; int data[MAX_NUM]; intdata2[max_num];

上述标识符第4行是编译不过的,即使max_num是两个int的统计数据类型表达式,数组表述的长度无法用表达式。实际上,在更章节第两个例子,只用于判断长度,#define更加合适,即使只要容许采用字面值自表达式的地方都能采用宏表述。

3、define只是单纯的字符串替换,没有类型检查。而const有对应的统计数据类型,是要进行判断的,能避免一些低级的错误。define只是单纯的字符串替换会导致边界效应,

比如表述

#define A 1 #define B A+3#define C A/B3

那么c是多少呢?c=A/B3=A/A+33=1/1+33=10;所以这种用的这时候能直接都用个括号括起来,就不怕边界效应了。

4、const无法重表述,无法表述两个一样的,而define就比较牛气了,它通过undef取消某个符号的表述,再重新表述。并还能用于判断宏表述是否存在,常用于头文件防止头文件被重复引用。

#ifndef GRAPHICS_H //防止graphics.h被重复引用#defineGRAPHICS_H ……标识符…… #endif

5、const自表达式能进行调试的,define是无法进行调试的,主要是预编译阶段就已经替换掉了,调试的这时候就没它了。

点击查看本文所在的专辑:

相关文章

发表评论
暂无评论
官方客服团队

为您解决烦忧 - 24小时在线 专业服务