C++的常量折叠(三)
背景知识
在开始之前先说一下符号表,这个编译器中的东西。下面看一下百度百科中的描述:
符号表是一种用于语言翻译器中的数据结构。在符号表中,程序源代码中的每个标识符都和它的声明或使用信息绑定在一起,比如其数据类型、作用域以及内存地址。
符号表在编译程序工作的过程中不断收集、记录和使用源程序中一些语法符号的类型和特征等相关信息。这些信息一般以表格形式存储于系统中。如常数表、变量名表、数组名表、过程名表、标号表等等,统称为符号表。对于符号表组织、构造和管理方法的好坏会直接影响编译系统的运行效率。
还有一个问题:前面说的似乎很让人烦,既然声明成了const,干嘛还老修改啊?
根据C++标准,对于修改const变量,属于:未定义行为(指行为不可预测的计算机代码),这样一来此行为取决于各种编译器的具体实现(即不同编译器可能表现不同)。
看到了吧,C++标准是不提倡这么玩的。
下面看一下前面说的那个对照程序:
int main()
{
int i0 = ; const int i = ; //定义常量i
int *j = (int *) &i; //看到这里能对i进行取值,判断i必然后自己的内存空间
*j = ; //对j指向的内存进行修改
printf("0x%p\n0x%p\n%d\n%d\n",&i,j,i,*j); //观看实验效果 const int ck = ; //这个对照实验是为了观察,对常量ck的引用时,会产生的效果
int ik = ck; int i1 = ; //这个对照实验是为了区别,对常量和变量的引用有什么区别
int i2 = i1; return ;
}
同时把i的声明那条语句改成:
const volatile int i = ; //定义常量i
我们知道volatile是告诉编译器在翻译源码到汇编语言(机器码)的过程中,不要优化。把源码中对i的访问,翻译成每次都要去内存中抓取数据(这里是在做编译工作,只是把对应的源码翻译成汇编语言),而不是从符号表(常量表)中抓取数据。所以加上volatile关键字的i的访问都是去内存中拿数据,不去常量表中。
现在还有个问题,如果我加上volatile关键字,那么每次对i的访问的语句都被翻译成了”去看内存里的数据“这种行为的汇编语言,不会有常量替换的过程了,那么下面的语句是不是合法了呢?
i = ;
你修改了常量的值,怎么可能合法呢?但是按照上面的说法对于const volatile int类型的i似乎又是合法的。问题出在了这里:
编译器的一部分工作流程是这样的:语法检测->预编译(宏替换,常量替换,*(&i)恒等于i等优化)->编译。所以i = 10这句话在语法检查这个阶段,看到你对一个const常量赋值,就已经报错了,根本到不了编译这个阶段。
但是有的一些编译器似乎无视这个volatile关键字,下面看一下测试的结果:
(1)看vc6.0的结果:
没有volatile关键字的:

有volatile关键字的:

即在VC++6.0编译环境下,在const变量定义时添加volatile修饰符,与不添加效果是一样的。编译器都采取了优化(甚至把编译器优化选项关闭还是如此,无奈了)。
(2)vs2010和g++的测试结果是一样的:
没有volatile关键字:

有volatile关键字:

所以:不建议修改const变量的值,即使修改也要熟悉当前使用的编译器对于该 未定义行为 是如何解释的。
C++的常量折叠(三)的更多相关文章
- java之常量折叠
为什么会写着篇博客,因为昨天看了关于final关键字的解析.但是有个问题始终没有得到解决,于是请教了我qq上之前添加的知乎大神.他给我回复的第一条消息:常量折叠.身为渣渣猿的我立马查询了这个概念.这是 ...
- C++高级进阶 第四季:const具体解释(二) 常量折叠
一.文章来由 const具体解释之二 二.const 取代 #define const最初动机就是取代 #define. const 优于 #define: (1) #define没有类型检查,con ...
- C++中的常量折叠
先看例子: #include <iostream> using namespace std; int main() { ; int * p = (int *)(&a); *p = ...
- 常量折叠 const folding
http://bbs.byr.cn/#!article/CPP/86336?p=1 下列代码给出输出结果: #include"stdafx.h" #include <iost ...
- const常量折叠
首先来看一个例子: int main(int argc, char* argv[]) { ; int *j = (int *) &i; *j=; cout<<&i<& ...
- C++的常量折叠(二)
前面的C++的常量折叠(一)的最后留下了一个问题,那就是在声明i的时候,加上修饰符volatile关键字,发现结果输出的就不一样了,下面来说一下volatile这个关键字. C/C++中的volati ...
- C++的常量折叠(一)
前言 前几天女票问了我一个阿里的面试题,是有关C++语言的const常量的,其实她一提出来我就知道考察的点了:肯定是const常量的内存不是分配在read-only的存储区的,const常量的内存分配 ...
- const常量,常量折叠,字面常量
const int a=10: 涉及到一个叫常量折叠的概念(认为我这说得太简单或者不好理解的可以google一下它获取更多信息), 即编译器虽然会给a分配空间(如果取a的地址进行操作的时候,会强迫编译 ...
- Python优化机制:常量折叠
英文:https://arpitbhayani.me/blogs/constant-folding-python 作者:arprit 译者:豌豆花下猫("Python猫"公众号作者 ...
随机推荐
- lighttpd配置虚拟主机/php等WEB环境
lighttpd(1.4.37)配置如下 server.document-root = "/var/www/lighttpd/" server.port = 8888 server ...
- spring bean之间的关系:继承;依赖
概要: ' 继承Bean配置 Spring同意继承bean的配置,被继承的bean称为父bean,继承这个父Bean的Bean称为子Bean 子Bean从父Bean中继承配置,包含Bean的属性配置 ...
- 杂记之activity之间的跳转
代码结构图 manifest.xml <?xml version="1.0" encoding="utf-8"?> <manifest xml ...
- Kali linux安装漏洞扫描工具Nessus指南
引子:Nessus是著名信息安全服务公司tenable推出的一款漏洞扫描与分析软件,号称是"世界上最流行的漏洞扫描程序,全世界超过75,000个组织在使用它".虽然这个扫描程序能够 ...
- 关于SYN洪泛攻击简介
在TCP三次握手中,server为了响应一个收到的SYN.分配并初始化连续变量和缓存.然后server发送一个SYNACK进行响应,并等待来自客户的ACK报文段. 假设某客户不发送ACK来完毕该三次握 ...
- [置顶] Guava学习之Splitter
Splitter:在Guava官方的解释为:Extracts non-overlapping substrings from an input string, typically by recogni ...
- HTML5增加的几个新的标签
HTML5又2008年诞生,HTML5大致可以等同于=html+css3+javascriptapi.... so --->支持css3强大的选择器和动画以及javascript的新的函数 先来 ...
- (转)eclipse 启动参数介绍(如添加插件时,如果不显示,则使用eclipse -clean启动)
本文转载自:http://hi.baidu.com/dd_taiyangxue/blog/item/08950f3991b4e8c9d46225c8.html 其实,Eclipse是一个可以进行非常灵 ...
- c++中派生类对基类成员的三种访问规则(转)
C++中派生类对基类成员的访问形式主要有以下两种:1.内部访问:由派生类中新增成员对基类继承来的成员的访问.2.对象访问:在派生类外部,通过派生类的对象对从基类继承来的成员的访问.今天给大家介绍在3中 ...
- Hadoop学习之shuffle过程
转自:http://langyu.iteye.com/blog/992916,多谢分享,学习Hadopp性能调优的可以多关注一下 Shuffle过程是MapReduce的核心,也被称为奇迹发生的地方, ...