作为C90增加的一个受限类型关键字,const赋予了它修饰的变量一个新属性——不变性,如果一个变量声明中带有关键字const,则无法通过赋值、增减运算来修改该变量的值。

一、指针与const结合

const与指针的结合较为复杂,因为我们需要把'让指针本身成为const'和'让指针指向的值成为const'区分开来。

1.1 int const *p

该声明表明我们声明了一个指针p,const在*左边,代表整个'*p'为不可修改的,也即p指向的值不可变。

  1. int a = 2;  
  2. int b = 10;  
  3.     
  4. const int *p = &a;  
  5.     
  6. printf("%x %d\n",p,*p);  
  7. *p = 4;  
  8. printf("%x %d\n",p,*p);  

尝试修改指针p指向的值,编译后报错:[Error] assignment of read-only location '*p',p指向的位置为只读。

修改一下a的值,看运行结果。

没有报错,a的值被成功修改。

再试一下,修改p的值:

  1.     int a = 2;  
  2.     int b = 10;  
  3.         
  4.     const int *p = &a;  
  5.     
  6.     printf("%x %d\n",p,*p);  
  7. //  *p = 4;     //[Error] assignment of read-only location '*p'   
  8.     p = &b;   
  9.     printf("%x %d\n",p,*p);  

运行成功,由结果能看出,const的只读限制只对*p起作用,而p、p指向的对象的操作(a)都可读可写。

再看一个,将有const的指针赋值给没有const的指针:

  1. int a = 2;  
  2. int b = 10;  
  3.     
  4. const int *p = &a;  
  5.     
  6. printf("%x %d\n",p,*p);  
  7. int *p1 = &a;  
  8. printf("%x %d\n",p1,*p1);  
  9. p1 = p;  

被const修饰的p与没有被修饰的p1值相同,指向位置的值也相同。不过在第九行'p1 = p;',弹出警告,继续运行:[Warning] assignment discards 'const' qualifier from pointer target type

1.2 int * const p

const在*右边,代表指针p不可修改,也即p总是指向同一个地址。

先修改个地址试一试。

  1. int a = 2;  
  2. int b = 10;  
  3.     
  4. int * const p2 = &a;   
  5. printf("%x %d\n",p2,*p2);  
  6. p2 = &b;      

第六行报错:[Error] assignment of read-only variable 'p2',p2为只读变量。

再折腾折腾,直接修改它指向的值,引用对象的值试试。

p2指向的地址都没变,只要不修改地址,其余的操作都可行。

1.3 const int * const p

第一个const表示p指向的值不可变,第二个const表示p本身不可变。也即p必须指向同一个位置,且所指位置存储的值也不可改变。

  1.     int a = 2;  
  2.     int b = 10;  
  3.         
  4.     const int * const p3 = &a;  
  5.     printf("%x %d\n",p3,*p3);  
  6.         
  7.     a = 3;  
  8.     printf("%x %d\n",p3,*p3);  
  9.         
  10. //[Error] assignment of read-only variable '*p3'  
  11. //  p3 = &b;  
  12.     printf("%x %d\n",p3,*p3);  
  13.         
  14. //[Error] assignment of read-only location '*p3'  
  15. //  *p3 = 1;      
  16.     printf("%x %d\n",p3,*p3);  

1.4 总结

当const与指针一同出现时,位于*左边的const使得数据成为常量,位于*const右边的const使得指针自身成为常量。更直白点来说就是:修饰谁,谁的内容就不可变,其余的都可变。

二、const与全局变量

由于程序的任何部分都可以修改全局变量的之,因此使用全局变量是一种很冒险的写法。但当我们用上了const后,这个问题就解决了。

2.1 extern

在一个工程中,如果我们在一个.c文件中声明了一个全局常量,在该工程其他文件中,对该全局常量的引用就需要使用关键字'extern'。

  1. /* file1.c---存放有全局常量的文件*/  
  2. const int num = 100;  
  3.     
  4. /* file2.c---需要引用全集常量的文件*/  
  5. extern const int num;  

2.2 include与static

通过将全局声明放入头文件.h中,可以不必再纠结在哪个文件定义了声明、哪个文件引用了声明。不过需要注意的是,在声明时,const前必须加上static关键字,否则每一个引用该.h的文件都会得到该数据的一个副本,从而导致不同文件间的数据交流出问题。

  1. /*constant.h*/  
  2. static const int num = 100;  

使用头文件的缺点在于每一次引用.h都复制了数据,当.h中含有大量的数据时,就会引发新的问题了。

[C语言]类型限定词const解析的更多相关文章

  1. 类型限定词——const

    类型限定词有三个:const  volatile restrict. const:一般也叫常量修饰符. 作用:是修饰变量,被修饰的变量就变成常量了,不能被二次修改了. const int a=12:a ...

  2. java内存分配和String类型的深度解析

    [尊重原创文章出自:http://my.oschina.net/xiaohui249/blog/170013] 摘要 从整体上介绍java内存的概念.构成以及分配机制,在此基础上深度解析java中的S ...

  3. 解剖SQLSERVER 第四篇 OrcaMDF里对dates类型数据的解析(译)

    解剖SQLSERVER 第四篇  OrcaMDF里对dates类型数据的解析(译) http://improve.dk/parsing-dates-in-orcamdf/ 在SQLSERVER里面有几 ...

  4. WCF 已知类型和泛型解析程序 KnownType

    数据协定继承 已知类型和泛型解析程序 Juval Lowy 下载代码示例 自首次发布以来,Windows Communication Foundation (WCF) 开发人员便必须处理数据协定继承方 ...

  5. C#匿名类型和动态解析减少定义传输类模板

    C#作为强类型语言,在序列化和反序列化(json)场景中对字符串解析常常需要定义强类型模板,造成编码上的繁琐.其实可以使用匿名类型和动态解析减少json序列化时候的数据模板定义: string a = ...

  6. 变量和基本类型——复合类型,const限定符,处理类型

    一.复合类型 复合类型是指基于其他类型定义的类型.C++语言有几种复合类型,包括引用和指针. 1.引用 引用并非对象,它只是为一个已存在的对象所起的另外一个名字. 除了以下2种情况,其他所有引用的类型 ...

  7. 【转】java内存分配和String类型的深度解析

    一.引题 在java语言的所有数据类型中,String类型是比较特殊的一种类型,同时也是面试的时候经常被问到的一个知识点,本文结合java内存分配深度分析关于String的许多令人迷惑的问题.下面是本 ...

  8. c语言类型修饰符及内存

    今天来学习一下c语言类型修饰符及内存分布 1.auto int a; 默认在内存 2.register int a; 限制变量定义在寄存器上的修饰符 编译器会尽量安排CPU的寄存器去存放这个a,如果寄 ...

  9. C语言类型(上)

    前提说明 格式说明:以[signed] int 为例 表明该类型的完整表达是 signed int 只不过signed可以省略 所以 int 也代表 signed int 类型 signed和unsi ...

随机推荐

  1. RxJava2 源码分析

    前言 很多项目使用流行的Rxjava2 + Retrofit搭建网络框架,Rxjava现在已经发展到Rxjava2,之前一直都只是再用Rxjava,但从来没有了解下Rxjava的内部实现,接下来一步步 ...

  2. Oracle EBS - Setup: 配置文件Profile

    http://blog.csdn.net/lfl6848433/article/details/8696939 Oracle EBS - Setup: 配置文件Profile 1.诊断Diagnost ...

  3. ASP.Net Core 2.2 MVC入门到基本使用系列 (四)

    本教程会对基本的.Net Core 进行一个大概的且不会太深入的讲解, 在您看完本系列之后, 能基本甚至熟练的使用.Net Core进行Web开发, 感受到.Net Core的魅力. 本教程知识点大体 ...

  4. 使用.NET Core 2.1的Azure WebJobs

    WebJobs不是Azure和.NET中的新事物. Visual Studio 2017中甚至还有一个默认的Azure WebJob模板,用于完整的.NET Framework. 但是,Visual ...

  5. A tiny program to benchmark image transpose algorithms

    Here is the code: #include <stdio.h> #include <xmmintrin.h> #include <windows.h> t ...

  6. Windows 环境下使用强大的wget工具

    安装 下载[http://www.interlog.com/~tcharron/wgetwin.html] 解压到目录 比如我解压到D:\Tool\wget 添加wget环境变量,这样使用就更方便了, ...

  7. RabbitMQ Java实例

    引入RabbitMQ的jar包 <dependency> <groupId>com.rabbitmq</groupId> <artifactId>amq ...

  8. Cassandra的数据模型

    Cassandra的数据模型可以理解为嵌套的Map,在Cassandra中数据类型主要有四种:Column,SuperColumn,ColumnFamily,Keyspace.下面分别介绍这几种类型. ...

  9. 【wireshark】总体结构

    1. 总体结构 wireshark的总体结构如下图所示. 2. 功能模块 模块名 功能 源码子目录 GTK/Qt 处理所有的用户输入/输出(所有的窗口,对话框等等) /ui GTK: /ui/gtk ...

  10. Python绑定方法与非绑定方法

    绑定方法 绑定方法(绑定给谁,谁来调用就自动将它本身当作第一个参数传入): 绑定到类的方法:用classmethod装饰器装饰的方法,类在使用时会将类本身当做参数传给类方法的第一个参数(即便是对象来调 ...