您的位置 首页 知识

C言语的那些小秘密之const修饰符

或许还有不少人对于const修饰符理解的并不深刻,都只是停留在一个比较浅的层面上,仅仅是在读别人代码的时候看到了const修饰符的使用,自己的写代码的过中从未使用过,所以自然对于const修饰符比较

         或许还有不少人关于const润饰符了解的并不深入,都仅仅停留在一个比较浅的层面上,仅仅是在读他人代码的时分看到了const润饰符的运用,自己的写代码的过中从未运用过,所以天然关于const润饰符比较生疏。那么究竟什么是const润饰符,咱们在自己编写C言语代码的进程中又该怎么有用的运用const润饰符呢,现在让咱们来学习下const润饰符的运用。

  const在C言语中算是一个比较新的描述符,咱们称之为常量润饰符,即便是说其所润饰的目标为常量。当你代码中想要设法阻挠一个变量被改动,那么这个时分能够挑选运用const要害字。在你给一个变量加上const润饰符的一同,一般需求对它进行初始化,在之后的程序中就不能再去改动它。

  或许有的人会有一个疑问,咱们不是有在C中有预处理指令#define VariableName VariableValue 能够很便利地进行值代替,干嘛还要引进const润饰符呢?!这是由于预处理句子尽管能够很便利的进行值得代替,但它有个比较丧命的缺陷,即预处理句子仅仅仅仅简略值代替,缺少类型的检测机制。这样预处理句子就不能享用C编译器严厉类型查看的优点,正是由于这样,使得它的运用存在着一系列的危险和局限性。

  在解说const润饰符之前,咱们在此首要给出const润饰符的几个典型效果:

  1. const类型界说:指明变量或目标的值是不能被更新,引进意图是为了替代预编译指令

  2. 能够维护被润饰的东西,避免意外的修正,增强程序的健壮性;

  3. 编译器一般不为一般const常量分配存储空间,而是将它们保存在符号表中,这使得它成为一个编译期间的常量,没有了存储与读内存的操作,使得它的功率也很高。

  4. 能够节约空间,避免不必要的内存分配。

  接下来看看详细的运用。

  一、const润饰符在函数体内润饰局部变量。

  const int n=5;

  和

  int const n=5;

  是等价的。咱们在编程的进程中必定要清楚的知道const润饰的目标是谁,在这儿润饰的是n,和int没有关系。const 要求他所润饰的目标为常量,不能被改动,一同也不能够被赋值,所以下面这样的写法是过错的。

  const int n;

  n=0;

  关于上面的状况是比较简略了解的,可是当const与指针一同运用时,就简略让人感到利诱。例如,下面咱们来看看一个p和q的声明:

  const int *p;

  int const *q;

  看了上面的代码或许有人会觉得 const int *p;表明的是const int类型的指针(const直接润饰int),而 int const *q;表明的是int类型的const指针(const直接润饰指针)。实际上,在上面的声明中p和q都被声明为const int类型的指针。而int类型的const指针应该这样声明:

  int * const r= &n;

  以上的p和q都是指向const int类型的指针,也便是说,你在今后的程序里不能改动*p的值。而r是一个const指针,它在声明的时分被初始化指向变量n(即r=&n;)之后,r的值将不再答应被改动,但*r的值能够改动。在此关于判别const的润饰目标给出一种常运用的办法,咱们以*为界限,假如const坐落*的左边,则const便是用来润饰指针所指向的变量,即指针指向为常量;假如const坐落*的右侧,const便是润饰指针自身,即指针自身是常量。

  仍是给个代码来加深下咱们的形象吧。

  #include

  int main(int argc, char* argv[])

  {

  int ss=9;

  int * const r= &ss;

  printf("%d\n",*r);

  printf("%d\n",ss);

  *r=100;

  printf("%d\n",*r);

  printf("%d\n",ss);

  return 0;

  }

  运转成果如下:

  

 

  简略的来剖析下吧,由于r指向的是ss的地址,所以修正r指向的地址单元的值的一同ss的值也随之改变。

  结合上述两种const润饰的状况,咱们现在应该能够完结怎么声明一个指向const int类型的const指针,如下:

  const int * const r=&ss;

  这个时分咱们既不能修正*r的值也不能修正r的值。

  接下来看看const用于润饰常量静态字符串,例如:例如:

  const char* str="fdsafdsa";

  假如没有const的润饰,咱们或许会在后边有意无意的写str[4]=’x’这样的句子,这样会导致对只读内存区域的赋值,然后程序会马上反常停止。有了const,这个过错就能在程序被编译的时分就当即查看出来,这便是const的优点。让逻辑过错在编译期被发现。

  二、const在函数声明时润饰参数

  void *memmove( void* dest, const void* src, size_t count ); 这是规范库中的一个函数,在头文件#include 中声明,其功用为由src所指内存区域仿制count个字节到dest所指内存区域。用于按字节方法仿制字符串(内存)。它的第一个参数,是将字符串仿制到哪里去(dst),是意图地,这段内存区域有必要是可写。它的第二个参数,是要将什么样的字符串仿制出去,咱们对这段内存区域只做读取,不写。所以,咱们站在这个函数自己的视点来看,src 这个指针,它所指向的内存内所存储的数据在整个函数履行的进程中是不变。所以src所指向的内容是常量。所以就需求用const润饰。别的需求侧重的一点便是src和dest所指内存区域能够堆叠,但仿制后dest内容会被更改。函数回来指向dest的指针。

  例如,咱们这儿这样运用它。

  #include

  #include

  int main(int argc, char* argv[])

  {

  const char* str="hello";

  char buf[10];

  memmove(buf,str,6);

  printf("%s\n",buf);

  return 0;

  }

  运转成果如下:

  

 

  假如咱们反过来写,memmove(str,buf,6);那么编译器必定会报错。事实是咱们常常会把各种函数的参数次序写反。事实是编译器在此刻帮了咱们大忙。假如编译器静悄悄的不报错,即在函数声明void *memmove( void* dest, const void* src, size_t count ); 处去掉const即可,那么这个程序在运转的时分必定会溃散。这儿还要阐明的一点是在函数参数声明中const一般用来声明指针而不是变量自身。例如,上面的size_t len,在函数完成的时分能够彻底不必更改len的值,那么是否应该把len也声明为常量呢?能够,能够这么做。咱们来剖析这么做有什么好坏。假如加了const,那么关于这个函数的完成者,能够避免他在完成这个函数的时分修正不需求修正的值(len),这样很好。可是关于这个函数的运用者,

  1.饰符号毫无意义,咱们能够传递一个常量整数或许一个十分量整数曩昔,横竖对方取得的仅仅咱们传递的一个copy。

  2完成。我不需求知道你在完成这个函数的时分是否修正过len的值。

  所以,const一般只用来润饰指针。再看一个杂乱的比如

  int execv(const char *path, char *const argv[]);

  侧重看后边这个,argv.它代表什么。假如去掉const,咱们能够看出char * argv[],argv是一个数组,它的每个元素都是char *类型的指针。假如加上const.那么const润饰的是谁呢?润饰的是一个数组,argv[]意思便是说这个数组的元素是只读的。那么数组的元素的是什么类型呢?是char *类型的指

  针.也便是说指针是常量,而它指向的数据不是。所以

  argv[1]=NULL; //不合法

  argv[0][0]=’a’; //合法

  三、const作为大局变量

  在程序中,咱们要尽或许少的运用大局变量。由于其效果域是大局,所以程序范围内都能够修正它的值,然后导致了大局变量不能确保值的正确性,假如呈现过错十分难以发现。假如在多线程中运用大局变量,你的程序将会错的乌烟瘴气。多线程会修正另一个线程运用的大局变量的值,假如不注意,一旦犯错后果不堪设想。所以在这种状况下万不满意不要运用大局变量。咱们要尽或许多的运用const。假如一个大局变量只在本文件中运用,那么用法和前面所说的函数局部变量没有什么区别。假如它要在多个文件间同享,那么就牵扯到一个存储类型的问题。

  有两种方法。

  1.用extern

  例如

  /* pi.h */

  extern const double pi;

  /* pi.c */

  const double pi=3.14;

  然后其他需求运用pi这个变量的,包括pi.h

  #include pi.h

  或许,自己把那句声明仿制一遍就好。这样做的成果是,整个程序链接完后,一切需求运用pi这个变量的同享一个存储区域。

  2.运用static,静态外部存储类

  /* constant.h */

  static const double pi=3.14;

  需求运用这个变量的*.c文件中,有必要包括这个头文件。前面的static必定不能少。不然链接的时分会陈述说该变量被屡次界说。这样做的成果是,每个包括了constant.h的*.c文件,都有一份该变量自己的copy,该变量实际上仍是被界说了屡次,占用了多个存储空间,不过在加了static要害字后,处理了文件间重界说的抵触。害处是浪费了存储空间,导致链接完后的可履行文件变大。一般来说,关于存储空间字节的改变不是太大的状况下,不是问题。优点是,你不必关怀这个变量是在哪个文件中被初始化的。

  下面再来看看一段代码:

  #include

  int main()

  {

  const int a=12;

  const int *p=&a; // 这个是指向常量的指针,指针指向一个常量

  p++; //能够指针能够自加、自减

  p–; //合法

  int const *q=&a; // 这个和上面const int *p=&a;是一个意思

  int b=12;

  int * const r=&b; //这个便是常量指针(常指针),不能自加、自减,而且要初始化

  //r++; //编译犯错

  const int * const t=&b; //这个便是指向常量的常指针,而且要初始化,用变量初始化

  //t++; //编译犯错

  p=&b; //const指针能够指向const和非const目标

  q=&b; //合法

  return 0;

  }

  为了便于代码的阅览了解,在此就直接在代码后边加注释,就不在这儿做过多的解说了。

  综上所述,const 的优点,是引进了常量的概念,让咱们不要去修正不应修正的内存。直接的效果便是让更多的逻辑过错在编译期被发现。所以咱们要尽或许的多运用const。以上内容不免有错,假如过错,请纠正!如需转载,请注明出处!

声明:本文内容来自网络转载或用户投稿,文章版权归原作者和原出处所有。文中观点,不代表本站立场。若有侵权请联系本站删除(kf@86ic.com)https://www.86ic.net/zhishi/116744.html

为您推荐

联系我们

联系我们

在线咨询: QQ交谈

邮箱: kf@86ic.com

关注微信
微信扫一扫关注我们

微信扫一扫关注我们

返回顶部