你的浏览器版本过低,可能导致网站不能正常访问!
为了你能正常使用网站功能,请使用这些浏览器。

c++-

[复制链接]
gaosmile 发布时间:2020-8-20 20:31
关于const的用法,现在大概前前后后应该写了有两篇文章,以前学习的时候,用法体会不是那么深刻,为啥这么说呢,因为在学习c++的时候,会发现const关键字有新的玩法,关于这个新的玩法,大家可以去看最近学习总结写的c++文章专辑。
一、const的用法:
1、const只读变量:
  • const修饰的变量是只读的,本质上还是变量
  • const修饰的局部变量在栈上分配空间
  • const修饰的全局变量在全局数据区分配空间
  • const只在编译期有用,在运行期没有用
    4 J3 E4 }; e- s. @* ^
注:const修饰的变量不是真的常量,它只是告诉编译器该变量不能出现在赋值符号的左边
2、const全局变量的分歧:
  • 在现代c语言编译器中,修改const全局变量将导致程序崩溃
  • 标准c语言编译器不会将const修饰的全局变量存储于只读存储区中,而是存储于可修改的全局数据区,其值依然可以改变
    # ~0 }% R! E6 c: b' G( _2 ]; q
3、代码示例:
(1)只读变量代码示例:
#include <stdio.h>
3 a' G9 I1 ^+ p
4 Z5 c: g5 [) q* s  M  r5 zint main()
4 H1 m8 d. A& z( b0 ]* |{; w7 |. X" H% \5 g
   const int a =10;: q5 H# i. e% v- B* ]
   printf("a = %d\n",a);
  ]6 p  R: H+ C! d: E! C7 H# m$ ^5 t# ?8 Z
   a=20;6 \2 d# @4 K8 J' `! n
   printf("a = %d\n",a);/ [1 N& N) e  Q7 ]
  
5 V4 m0 t5 ~  j1 \7 q  return 0;  ]5 n' a4 @; o8 m! c9 {/ X& n
}
; j8 @7 {& b# J, p  ~4 k& \& @( R: W- l8 d2 Z" N
运行结果:
test.c: In function ‘main’:5 [8 L3 E  V$ R+ u
test.c:8:4: error: assignment of read-only variable ‘a’
  T: |7 n" m% }; }    a=20;
* F- }( a( K0 F7 g& h    ^
2 \8 H, _3 F" I- o0 j
, K% _! @( ^8 B4 a& D) e
注解:显示这个结果很正常,变量a被const修饰了,它就成了只读的。
(2)如果对变量a的值进行修改:
#include <stdio.h>
2 e" j) ?( w6 I- H$ V( k/ _
- k' d% M- q0 _5 z1 ~int main()
. I( t& N* C! [{
7 V3 B" ?& c) ], d$ O, y   const int a =10;
+ S0 Q- r! [1 `/ E& w; ?# k* c   int *p =(int *) &a;: e( z8 ~% A3 t  u( b
   printf("a = %d\n",a);4 \- C% g' b0 u9 l- N
7 ^, N3 ^4 f' i& a5 C# A
   *p=20;5 V: W/ s; s5 S! c* s
   printf("a = %d\n",a);, g3 D7 f# f( r0 W

7 e5 i: A7 H& L
* G: p; I4 R  M1 d( U3 B  return 0;
( v; _: _' c/ c9 X}+ O" @  e- z2 o. Z
! X) f+ a6 X9 x( S: e8 E! Z

9 X2 j" o9 H+ ]" H0 l
运行结果:
root@txp-virtual-machine:/home/txp# ./a.out+ A' K' [6 Q# {$ e  |, E! n
a = 10
. Z2 ?4 l- F, pa = 20
1 W: u4 n$ ^: p+ q
" R! G- z+ d3 A! K0 T3 J# G
注解:通过指针的方式,就能够把a的值进行修改,这也论证了“const修饰的变量是只读的,本质上还是变量”这句话
(3)const修饰全局变量:
代码版本一
#include <stdio.h>; X7 E0 j) V% c( O! b; w
const int b = 40;' s! i3 l2 B4 H9 t1 h) }

4 y+ I7 z# Y# f1 zint main()
' w3 [0 Q' D1 J7 j4 B$ ?+ a8 _{
' `2 W5 R2 j4 |/ |2 d5 c# X. L   
- y( z( X- g+ _: T% X$ r8 k5 ? ( J0 Q$ @8 x/ U- r) G
   printf("b = %d\n",b);6 P7 q' Q; p5 c0 v
   b=20;  [8 t7 S. \! v" F, Z$ E5 _
   printf("b = %d\n",b);
' ^! ?0 Y! O, e2 p( a2 x, H# r7 a3 k  d7 u

& l, p) k- n' h% N  return 0;
  E: O+ x9 D4 {/ [. o}  X4 H# B' F* t6 p' _1 P

: }5 n  w% b8 E) I$ l% z% x6 q
输出结果:
root@txp-virtual-machine:/home/txp# gcc test.c
7 ]0 y. r# E" \9 h( ~2 gtest.c: In function ‘main’:, s3 j+ M: ]8 e
test.c:10:4: error: assignment of read-only variable ‘b’
/ g5 @% n2 Y* O: M# J    b=20;: d8 B+ c) B; Z+ F# \) A
    ^0 \  [9 x. y" V3 C( w6 L

& \4 t2 T5 S" U' C! Z, E8 H7 S
注解:跟const修饰栈上的变量用法一样
代码版本二
#include <stdio.h>! i& ^" l% Y0 a% R1 p7 a2 d0 z! F% t' V
const int b = 40;
8 Q/ N) F) `3 P2 {% v$ O
5 e; i) @' r; j* f* T( rint main()+ H& t7 }7 ?* S8 j
{7 n0 }' I) Q( }! V' O
  a/ Z: h: K% p
   int *p =(int *) &b;9 |2 y  X. I- ~2 t) |, T
   printf("b = %d\n",b);
7 ]( o" h" h% [3 c* D. U4 W
) t0 H6 x; ?* H8 n! t7 A) m   *p=20;$ [6 R0 N( t2 p
   printf("b = %d\n",b);
! I: `- ]$ ~$ G3 U" w: N' R2 q; R9 U, V, s# m
& m& Z6 N$ c' x$ }7 x
  return 0;
; C- V: J( K1 `6 `2 H  ~}3 p2 \! L6 H2 Z
6 z2 Q6 H7 i- `4 C  S: a" V
运行结果:
root@txp-virtual-machine:/home/txp# ./a.out
4 }" [( K( ~0 cb = 401 m" b( Q3 U& a4 T' d4 u
Segmentation fault (core dumped)
8 s$ L5 p1 D" r+ t# o. R% t6 R+ u* I: P$ s6 {! V) P
注解:这里出现了段错误,这也验证了我们上面所说的“修改const全局变量将导致程序崩溃”。
同时为了验证“标准c语言编译器不会将const修饰的全局变量存储于只读存储区中,而是存储于可修改的全局数据区,其值依然可以改变”这句话,我把这段代码放到dev c++上进行试验:
微信图片_20200820202426.png
说明:我这个版本的编译器支持标准c语言,所以没导致程序崩溃,能够正常运行
4、const的本质
  • c语言中的const使得变量具有只读属性
  • 现代c编译器中的const将具有全局生命周期的变量存储于只读存储区,不是放在全局数据区

    , Q! I! k  Z- j) [% M+ W
注:const不能定义真正意义上的常量;同时这里注意static关键字修饰的变量,它的生命周期和全局变量一样。
代码示例:
#include <stdio.h>7 e8 g9 e( Q9 r( e5 l  Z( p- H; T
/ f4 @8 K8 n* _4 {$ h' {
const int Array[5] = {0};
# l% X, y* P' [6 @* Q* M* R$ J8 s  h" s' E8 N4 H# S: z- u
void fun(int *p,int v)
9 g7 W* f' R, w( N# p# m6 R. ~{
5 j; G. \/ P1 F$ \2 n   *p=v;2 t  f& ]8 B' v, P7 U
}
6 U' {( \, t$ O- o. Yint main()6 E. Y. }+ m" n) R- ~
{
: t4 _: \1 Q% o    int const i =1;
- O( n% L% P) `5 g    const static int j =2;
2 s/ B% @, p2 a& l    int const array[5] = {0};7 a4 W: z+ F! |: T5 C4 c- [
" z( Q8 W/ i* o, |1 s9 [# l
    fun((int *)&i,1);. Q! U: T$ q3 e+ m- n1 s% W, q
    fun((int *)&j,2);% t0 J1 l* P. V9 b; ~
    fun((int *)&array[2],3);( x! r+ k  f9 \  M" B; P3 I" d  S
    fun((int *)&Array[1],4);& T) H/ i4 S; h: T: n* v
3 D, O1 P% k/ v4 |# S# ]4 a3 ?
   return 0;0 I$ I: R) c& |  W) z1 Y

4 p8 k  o3 A+ H1 o  C% \) |  }. D/ [' ~}
2 B, M- T' g. r' @' y7 B, G; f
% {2 s8 \- C$ E8 U
输出结果:
root@txp-virtual-machine:/home/txp# ./a.out
& a. U# \/ R$ B: Y) {, y$ FSegmentation fault (core dumped)
+ C' |4 y7 m* Y5 L: g7 ?: }; c, O$ Q/ p: U  u7 l
注解:这里会有段错误,错误出现在const+static修饰的j变量对其进行修改,还有const修饰的全局数组。
5、const修饰函数参数和返回值
  • const修饰函数参数表示在函数体内不希望改变参数的值
  • const修饰函数返回值表示返回值不可改变,多用于返回指针的情形
    " _* D# I- D( d
在c语言中的字符串字面量存储于只读存储区中,在程序中需要使用const char* 指针,例如:
const char * s = "TXP嵌入式";//字符串字面量0 x- y5 X+ c' |. J: G! s( \
代码示例:
#include <stdio.h>
& K9 D$ \: b- _5 o- X6 F4 T. n
1 a% H- |. z# b$ ~& i) v$ P& M' `. Xconst char*fun(const int i)
! i, n3 y% @  x7 n" I- v5 M{
$ \; p" g6 m% }2 V5 o4 F& ]6 p   i=8;
4 ?( _, h& y* i6 p7 f4 W    return "TXP";
* c+ Q1 p; E" Y" }}
1 y5 u0 R; z* H/ ~, bint main()
' G+ K  t+ J) H{
& q* L8 Q4 v9 u* g) G5 l' x( e   const char * p=fun(0);! j: o: L4 w7 _& p3 X7 O) i. ^
    printf("%s\n",p);
* I; V; h. t. b6 K" S6 X    p[1]='_';6 L) q0 g) Q2 j6 y" ~% ?
    printf("%s\n",p);
, ?, w7 F. [. h+ H
. B% y9 u: m1 x# W  _% ^    return 0;
( Y$ O. S1 R; |' x# G
4 t+ Q8 U8 j, S5 D: u; }2 F1 m1 x" k+ O5 B
}9 w  B: b  A: ?
, J$ Z  R) J: ?( g1 ~
& ]8 g2 u1 ?; J! z  ?: |0 ~8 ]
输出结果:
root@txp-virtual-machine:/home/txp# gcc test.c4 O. ~- }: c! j+ J4 O+ z
test.c: In function ‘fun’:: O9 c  H8 }$ `* G
test.c:5:4: error: assignment of read-only parameter ‘i’- o. A) f2 S* n1 ^
    i=8;
0 r3 \; ~6 o  q# R3 F    ^
( _$ F9 G) ^, V" A2 L2 ?test.c: In function ‘main’:& Q* A  o  C  W
test.c:12:5: error: assignment of read-only location ‘*(p + 1u)’
$ R+ G$ n% ?/ T, z& X# m     p[1]='_';
: r0 h/ w5 l. s  a$ ~+ Q3 v     ^
+ k. ]" Z; d9 B- Y0 S
) y( s5 D' y5 B/ o( Z% m* ?
注解:上面这样写,肯定有问题。
代码进化:
#include <stdio.h>
/ g) Q- K9 ~3 Z  k' W& S0 x$ u0 i, i1 ?5 a+ N
const char*fun(const int i)
4 m. w, \5 ?2 s5 Q0 w9 u# l{
; v( {1 D- i  t2 [+ O//   i=8;0 T0 s1 B; }8 ~4 z
    return "TXP";3 w8 Z2 [" h! ^, r1 z5 z9 m( H1 A
}& y2 |- Y* U' N% A$ f8 ^
int main()7 {# u3 y6 L, |5 ?* G9 ~
{
+ ~$ M, \4 ~9 I9 C   const char * p=fun(0);+ c! Y, @2 s* b
    printf("%s\n",p);9 V  P0 G- D* [/ f# N( A; w. ]* L
  //  p[1]='_';* V4 w# s( `% Q( Y8 @
   // printf("%s\n",p);2 o: ]/ c* j  p3 N0 F

; ~+ j9 d# }4 e8 `    return 0;* s# g% c: f5 O1 k

8 m$ Y4 _# x8 \+ ]# g1 [  Y! `* \, ]  m) J4 F: b
}) r, J. F- M5 X4 C0 W( ]8 s' `5 n$ ?

& y; V) Q. h0 @, k& T7 K
输出结果:
root@txp-virtual-machine:/home/txp# ./a.out
1 x" @) ]- V" b* rTXP% g0 R+ N: q5 z. x

% G4 @7 B5 \, [  l
二、volatile的用法
老实说,这个关键字在面试题目里面经常会出现,但是平时学习的时候,如果你没有真正理解这其中的含义,在笔试的时候,脑袋里面可能依稀是记得有那么几个结论,但是有时候吧,一紧张就把结论给忘了,也不是不可能,所以说,咋们还是老实一点,得真正把它原理搞明白才行,这样上来战场就不怕了,以后写代码也就少一点bug。
1、volatile的常用结论(volatile英文本意就是易变的意思)
这里我先给结论,然后再给一个例子,把这个例子的讲明白,所有结论就都明白了。
  • volatile可理解为“编译器警告指示字”
  • volatile告诉编译器必须每次去内存中取变量值
  • volatile主要修饰可能被多个线程访问的变量
  • volatile也可以修饰可能被未知因素更改的变量
  • volatile可以修饰一个中断子程序中会访问到的非自动变量

    2 L8 [2 u1 P' f8 L  [4 O5 M$ P! O7 k
2、分析原理
大家可能平时在博客学习,都会发现讲解编译器优化的,然后加了volatile关键来修饰变量,就告诉编译器不要去优化这个变量了,那么这里的优化到底是什么意思呢?
从字面上来理解优化两个字,意思就是最优值(变量的值不会改变),这里我用一个简单代码来说明一下:
#include <stdio.h>
; T1 H# Q' y5 ]
% M- k$ p7 s5 Lint main()7 O! R% l: a$ i8 b+ b4 O4 z: S9 i0 `
{
7 V4 O- k4 w  r    int a =1;//volatile int a =0;
+ Q. |$ B1 s- x7 d4 _- v( c) k" a     
4 j2 x# l- V& B  e    while(a)
- P9 I6 \  K* l# `, j# d0 y/ Y* l    {
4 a/ {8 C( g2 q   
$ S( l5 O  |7 e6 B* V    }
- V6 N1 b2 i( B}
. I. o' [) `; O' i# n
说明:上面的代码,如果变量a没有加volatile修饰的话,编译器就会优化它(也就是a的值一直不变),所以while就一直死循环;然后我如果加了volatile来修饰的话,编译器就不会去优化变量a,不优化的意思就是说,变量a的值可能就会改变,while就不会一直死循环。
当然这里为了好理解,我说的不是很专业,没有从寄存器和内存的角度去说。(我也不想那么去讲解,简单理解了就行)
总之一句话:上面的结论中,volatile修饰的都是变量,变量就可能改变,不会被编译器优化;只是说我们上面的结论应用场景不同而已。
三、总结
  • const使得变量具有只读属性
  • const不能定义真正意义上的常量
  • const将具有全局生命周期的变量存储于只读存储区
  • volatile强制编译器减少优化,必须每次从内存中取值
    2 V" m; M" N* Q9 c7 g. n
微信图片_20200820202430.png

1 {, A8 Q8 A$ p2 `1 I% \, Y
好了,今天的分享就到这里,如果文章中有错误或者不理解的地方,可以交流互动,一起进步。

& Y# B: n( J3 h: Z  ]. i5 t* |
赞 收藏 评论0 发布时间:2020-8-20 20:31

举报

0个回答

所属标签

关于
我们是谁
投资者关系
意法半导体可持续发展举措
创新与技术
意法半导体官网
联系我们
联系ST分支机构
寻找销售人员和分销渠道
社区
媒体中心
活动与培训
隐私策略
隐私策略
Cookies管理
行使您的权利
官方最新发布
人形机器人运动控制、感知与智能配电
半导体创新技术与应用方向
EE架构与软件定义汽车
12V/48V 汽车智能配电(SPD)
区域控制单元(ZCU)与分区架构
关注我们
st-img 微信公众号
st-img 手机版