C语言进阶——const 和 volatile 分析09
const只读变量:
- const修饰的变量是只读的,本质还是一个变量
- const修饰的局部变量在栈上分配空间
- const修饰的全局变量在全局函数区分配资源空间
- const只在编译器有用,在运行期无用
注意:const修饰的变量不是真的常量,他只是告诉编译器该变量不能出现在赋值符号的左边
const全局变量的分歧:
- 在现代C语言编译器中,修改const全局变量将导致程序崩溃
- 标准C语言编译器不会将const修饰的全局变量存贮于只读存贮区中,而是存贮可修改的全局数据区,其值依然可以改变
程序实例1:
#include <stdio.h> const int g_cc = ; int main()
{
const int cc = ; int* p = (int*)&cc; printf("cc = %d\n", cc); *p = ; printf("cc = %d\n", cc); p = (int*)&g_cc; printf("g_cc = %d\n", g_cc); *p = ; //error printf("g_cc = %d\n", g_cc); return ;
}
这段代码说明,const修饰的局部变量可以使用指针修改,但是const修饰全局变量不可以通过指针进行修改,第21行代码试图修改const修饰全局变量,由于我使用的codeblocks,是一款现代编译器,所以编译阶段会报错,删掉21行代码程序就可以正常运行
const的本质:
- C语言的const使得变量具有只读属性
- 现代C编译器中的const将具有全局生命周期的变量存贮于只读存贮区
- const不能顶第一真正意义上的常量
程序示例2:
#include <stdio.h>
const int g_array[] = {};
void modify(int* p, int v)
{
*p = v;
}
int main()
{
int const i = ;
const static int j = ;
int const array[] = {};
modify((int*)&i, ); // ok
modify((int*)&j, ); // error
modify((int*)&array[], ); // ok
modify((int*)&g_array[], ); // error
printf("i = %d\n", i);
printf("j = %d\n", j);
printf("array[0] = %d\n", array[]);
printf("g_array[0] = %d\n", g_array[]);
return ;
}
第3行和第13行声明了用const修饰的具有全局生命周期的变量,所以在试图用指针来修改他们的值的时候,编译器会报错
const修饰函数参数和返回值:
- const修饰函数参数表示在函数体内不希望改变参数的值
- const修饰函数返回值表示返回值不可改变,多用于返回指针的情形
- 小贴示:C语言的字符串字面量存贮于只读存贮区中,在程序中需要使用const char* 指针
程序实例3:
#include <stdio.h> const char* f(const int i)
{
i = ; return "Delphi Tang";
} int main()
{
char* pc = f(); printf("%s\n", pc); pc[] = '_'; printf("%s\n", pc); return ;
}
这段代码是错误的,但是我们来剖析一下,首先编译的时候第5行会出错,我们注释掉,接下来再编译,在12行会给出一个警告,我们用一个char *类型来接受了一个字面值常量,因为只是警告,所以我们可以运行一下,最后运行的时候还是出错了,因为第16行尝试修改了一个字面值常量
深藏不露的volatile:
- volatile 可以理解为 “编译器警告指示”
- volatile 告诉编译器必须每次去内存中去该变量值
- volatile 主要修饰可能被多个线程访问的变量
- volatile 也可以修饰可能被未知因数更改的变量
示例程序4:
int boj = ; //编译器在编译的时候发现obj int a=;
int b=; a= obj; //“聪明“的编译器不会到内存中去找obj对应的值,而是直接替换为10 sleep(); //在另一个线程里面可能已经改变了obj的值 b= obj; //这个时候编译器还是自作聪明的用10来代替obj,而不去内存中去找obj对应的值
这段代码只是一个小的片段,但是已经可以帮助我们理解有的时候编译器的自作聪明可能会导致某些bugconst volatile int i = 0;但是如果在定义一个变量的时候我们加上volatile属性,编译器每次就会去内存中去找到变量对应的值。
小结:
- const 使得变量具有只读属性
- const 不能定义真正意义上的常量
- const将具有全局生命周期的变量存贮于只读存贮区
- volatile 强制编译器减少优化,必须每次从内存中取值

C语言进阶——const 和 volatile 分析09的更多相关文章
- 第9课 - const 和 volatile分析
第9课 - const和volatile分析 1. const只读变量 (1)const修饰的变量是只读的,本质上还是变量,并不是真正意义上的常量 ※※ const只是告诉编译器该变量 ...
- 第9课 const和volatile分析
1. const只读变量——(注意不是真正常量,只是告诉编译器不能出现在赋值号左边!) (1)const修饰的变量是只读的,本质还是变量 (2)const修饰的局部变量在栈上分配空间 (3)const ...
- const和volatile分析
c语言中const修饰的变量是只读的,不能直接作为赋值号的左值,其本质还是变量:会占用内存空间:本质上const在编译器有用,运行时无用(还是可以通过指针改变它的值) ; int *p=&ab ...
- C语言进阶——enum, sizeof, typedef 分析11
枚举类型的使用方法: enum是C语言的 一种自定义类型 enum值是可以根据需要自定义的整型值 第一个enum的值默认为0 默认情况下的enum值是在前一个定义值的基础上加 1 enum类型的变量只 ...
- C语言进阶——struct和union分析10
struct的小秘密: C语言中的struct可以看作变量的集合 struct的问题:空结构体占用多大内存呢? 程序实例1: #include <stdio.h> struct TS { ...
- 《C语言进阶剖析》课程目录
<C语言进阶剖析>学习笔记 本文总结自狄泰软件学院唐佐林老师的<C语言 ...
- C语言-const和volatile深度分析
1.const只读变量 const修饰的变量是只读的.本质还是变量 const修饰的局部变量在栈上分配空间 const修饰的全局变量在全局数据区分配空间 const只在编译期有用,在运行期无用 con ...
- C语言中关键字auto、static、register、const、volatile、extern的作用
原文:C语言中关键字auto.static.register.const.volatile.extern的作用 关键字auto.static.register.const.volatile.exter ...
- 【R笔记】R语言进阶之4:数据整形(reshape)
R语言进阶之4:数据整形(reshape) 2013-05-31 10:15 xxx 网易博客 字号:T | T 从不同途径得到的数据的组织方式是多种多样的,很多数据都要经过整理才能进行有效的分析,数 ...
随机推荐
- Strut2_声明式异常处理
Service 往外抛异常 public List<Category> list() throws SQLException{ Connection conn = DB.createCon ...
- 利用html5的FormData对象实现多图上传
<html> <head> <title>FormData多图上传演示</title> </head> <body> <a ...
- 自顶向下理解Java集合框架(三)Map接口
Map基本概念 数据结构中Map是一种重要的形式.Map接口定义的是查询表,或称查找表,其用于储存所谓的键/值对(key-value pair),其中key是映射表的索引. JDK结构中还存在实现Ma ...
- check_mk插件 redis
/usr/lib/check_mk_agent/plugins/mk_redis #!/bin/bash echo '<<<redis>>>' hosts=$(ne ...
- Springboot中SpringMvc拦截器配置与应用(实战)
一.什么是拦截器,及其作用 拦截器(Interceptor): 用于在某个方法被访问之前进行拦截,然后在方法执行之前或之后加入某些操作,其实就是AOP的一种实现策略.它通过动态拦截Action调用的对 ...
- python3绘图示例2(基于matplotlib:柱状图、分布图、三角图等)
#!/usr/bin/env python# -*- coding:utf-8 -*- from matplotlib import pyplot as pltimport numpy as npim ...
- IOS NSOperationQueue(线程 封装操作)
#import "HMViewController.h" @interface HMViewController () @end @implementation HMViewCon ...
- SQL语句关于时间的查询小心得,希望大家给点意见
完全使用时间函数去搞定查询日期,之前写的可能有些问题,现在删了修正一下 本月记录: SELECT * FROM 表 WHERE datediff(month,[dateadd],getdate())= ...
- 2018.7.31 oracle rownum的理解
一.Rownum的描述: rownum是一个伪列,数据库中并不保存rownum的列值,它是oracle系统为返回的结果集顺序分配的行编号,rownum是随着结果集生成的,一旦生成,在同一个结果集中就不 ...
- Python 3 collections.defaultdict() 与 dict的使用和区别
综述: 这里的defaultdict(function_factory)构建的是一个类似dictionary的对象,其中keys的值,自行确定赋值,但是values的类型,是function_fact ...