内存中的static、const实现形式
最近在考虑下半年找工作的事情,看了不少面试题目,其中还是蛮有收获的,把基础好好复习了一遍。比如这个题目,static、const现形式,static和const类型的变量在写程序的时候也写了很多,不过对编译器内部对其实现知之甚少。所以借这次机会好好百度谷歌了一番。
static实现形式
我们都知道,static变量只能初始化一次,这个是怎么实现的呢?小齐的网易博客里面作者写的很清楚: 代码如下:
int main(){
for (int i(); i > ; --i)
{
fun(i) ;
}
return ;
}
void fun(int i)
{
static int n = i ;
int *p = &n ;
cout << n << " " ;
++n ;
}
因为static变量只能被初始化一次,所以第12行的初始化语句只会被执行一次,但是以后每次都会执行++n的操作,所以输出的结果是:
10 11 12 13 14 15 16 17 18 19
之后作者在VS下面对上述程序进行了DEBUG调试,发现第一次n被赋值之前内存如下:
0042E058 00 00 00 00 ....
0042E05C 00 00 00 00 .... // 中间这个为n的内存地址
0042E060 00 00 00 00 ....
当初始化语句执行完毕,内存内容如下:
0042E058 01 00 00 00 ....
0042E05C 0A 00 00 00 ....// n
0042E060 00 00 00 00 ....
作者继续执行,当for循环执行的时候,再次对static n初始化的时候,却发现n值不会等于i,而是继续保留原来的值。由此作者推断上面的那个0x01是不是就是标志n已经被初始化的标志位。即当要对n初始化的时候,就会检查上面的0042E058单元中对应的标志位是否是1,若是1,则说明已经初始化,若不是1,则进行初始化。
鉴于此,作者改进了fun函数,如下:
void fun(int i)
{
static int n = i ;
int *p = &n ;
cout << n << endl ;
++n ; p--;
*p=;
}
即每次修改0042E058内容清零,使得可以反复对n初始化,做了上述改动之后,函数执行的结果如下:
10 9 8 7 6 5 4 3 2 1
得到证实了,即即当要对static初始化的时候,就会检查上一单元中对应的标志位是否是1,若是1,则说明已经初始化,若不是1,则进行初始化。
之后作者又做了实验,他设定了两个static变量:
void fun(int i)
{
static int n1 = i ;
static int n2 = i ;
int *p = &n1 ;
cout << n1 << endl ;
++n1 ; p--;
*p=;
}
观察单元发现,当执行static赋值之前,内存单元内容如下:
0042E058 00 00 00 00 ....
0042E05C 00 00 00 00 .... // n1
0042E060 00 00 00 00 .... // n2
当执行完static int n1 = i 语句之后,内存的值变成这样了:
0042E058 01 00 00 00 ....
0042E05C 0A 00 00 00 ....
0042E060 00 00 00 00 ....
接着我们再单步static int n2 = i,则执行内存的值变成这样:
0042E058 03 00 00 00 ....
0042E05C 0A 00 00 00 ....
0042E060 0A 00 00 00 ....
这样就很明显了,编译器分别用一位来表示一个static变量是否已经始化。
const实现形式就比较简单了,作者想使用地址的形式改变const常量的值,可是没有成功,作者查看汇编代码,原来是编译器直接将常量类型的换成对应的数值了。这样在执行的时候直接使用数值替换。
至于const类型的变量,大家知道,在c语言中,下面的语句:
const int conVal=;
int *cPointer=&conVal;
是完全可以编译通过的,而且如果后面你通过*cPointer来改变conVal的值,也是大大的可以的,完全没有任何问题,编译器顶多弄一条警告而已。但是如果是在C++编译环境下面的话,再写上面两句话……结果%>_<%啊哦,那是一个错误“invalid conversion from 'const int*' to 'int*' [-fpermissive]|”。这时候如果我们还是想改变他们的值,那该怎么办呢?const_cast就出场了。
const int constant = ;
const int* const_p = &constant;
int* modifier = const_cast<int*>(const_p);
*modifier = ;
编译运行成功O(∩_∩)O~。但是问题又来了,
cout << "constant: "<< constant <<endl;//
cout << "const_p: "<< *const_p <<endl;//
cout << "modifier: "<< *modifier <<endl;//7
cout << "constant: "<< &constant <<endl;//0x22fef4
cout << "const_p: "<< const_p <<endl;//0x22fef4
cout << "modifier: "<< modifier <<endl;//0x22fef4
等等,这谁能告诉我,到底发生了什么事情?同一个地址的东西,我换个方式读取,值就不一样?不过这也证实了一件事情,在C++确实不愧是多了两个+,constant变量必须是constant的,那就是不变,不论怎么cast,我就是不变。
IBM的C++指南:“*modifier = 7;”为“未定义行为(Undefined Behavior)”。所谓未定义,是说这个语句在标准C++中没有明确的规定,由编译器来决定如何处理。
好吧,这指南都说了,未定义行为,由编译器决定处理方式,那咱就不多说什么了吧。不过上面这种使用方式真的只能是纯属测试行为,我们在实际中用到const_cast一般是有两种情况:
定义了一个const变量,但是却需要把这个变量传递到一个没有const修饰的参数的函数中去:
void aTest(int* a){
//do something, this will not change the *a
}
int main(){
const int val=;
aTest(const_casr<int *>(&val));
return ;
}
定义了一个普通变量,中间是用了const指针,但是现在确又想把它变回来了……
int variable = ;
const int* const_p2 = &variable;
int* modifier2 = const_cast<int*>(const_p2);
*modifier2 = ;
cout << "variable:" << variable << endl;
其实对于const变量,是没有运行时检查的,只有在编译器编译的时候才会进行检查。而且在某些情况下,是会直接使用const变量进行替换的,如数组长度等情况。某些同学可能还会问const char* str="abdd"这个语句中,里面的字符串为什么有写保护呢?其实这个嘛,可以理解为这个字符串是放在常量区的,放在一个只读属性的页面上面,所以在改写的时候是会出错的。这个跟前面的const定义是没有关系的,因为就算没有const修饰,这个字符串也是不能修改的。
内存中的static、const实现形式的更多相关文章
- OC中extern,static,const的用法
1.const的作用: const仅仅用来修饰右边的变量(基本数据变量p,指针变量*p). 例如 NSString *const SIAlertViewWillDismissNotification; ...
- const(每个对象中的常量), static const(类的编译时常量)
1 每个对象中的常量 --- const数据成员 const限定,意味着“在该对象生命周期内,它是一个常量”. 关键字const 使被限定的量为常量 在该类的每个对象中,编译器都为其const数据成员 ...
- c中常用的关键字static const volatile
在C语言中,关键字static有三个明显的作用:1). 在函数体,一个被声明为静态的变量在这一函数被调用过程中维持其值不变.2). 在模块内(但在函数体外),一个被声明为静态的变量可以被模块内所用函数 ...
- C++中类中常规变量、const、static、static const(const static)成员变量的声明和初始化
C++类有几种类型的数据成员:普通类型.常量(const).静态(static).静态常量(static const).这里分别探讨以下他们在C++11之前和之后的初始化方式. c++11之前版本的初 ...
- PC逆向之代码还原技术,第一讲基本数据类型在内存中的表现形式.浮点,指针寻址公式
目录 代码还原技术 一丶简介代码还原 二丶代码还原中的数据类型表现形式 1.整数类型 2.无符号整数 3.有符号整数 4.浮点数数据类型 5.浮点编码 4.Double类型解析. 三丶浮点汇编 1.浮 ...
- static const vs. extern const
在实现文件(.m文件)中使用static const来定义“只在编译单元内可见的常量”(只在.m文件内可见),由于此类常量不在全局符号表中,所以无须为其名称加类名前缀(一般以k开头). 在头文件中使用 ...
- iOS—— static和const联合使用;使用static const 与 #define
static和const联合使用: static将一个全局变量变成局部变量 const将一个局部变量变成局部常量 // 定义了一个局部常量 static const CGFloat ...
- static const readonly
C#中的static 和Java中的static 简单,两者用法完全是一致的.从两方面讨论: 1. 变量是属于类的,不是实例级别的.只能通过类名调用,不能通过实例调用. 2. 如果在定义时就赋值了,那 ...
- C语言 const, static, static const 的区别
基本定义: const 就是只读的意思,只在声明中使用;static 一般有2个作用,规定作用域和存储方式. 对于局部变量, static规定其为静态存储方式, 每次调用的初始值为上一次调用的值,调 ...
随机推荐
- 如何在Android studio中同时打开多个工程? (转载)
最近学习Android Studio,想同时打开两个Project.但是点击File->Open之后,原有的Project被关闭掉了.怎么在新的窗口中打开Project呢? 解决: 点击Help ...
- HDU 4324 (拓扑排序) Triangle LOVE
因为题目说了,两个人之间总有一个人喜欢另一个人,而且不会有两个人互相喜欢.所以只要所给的图中有一个环,那么一定存在一个三元环. 所以用拓扑排序判断一下图中是否有环就行了. #include <c ...
- 51nod1757 大灾变
能想到二分答案+最大流判断是否符合.但是不知道如何建图qaq.参考的是http://blog.csdn.net/fsss_7/article/details/52132046的建图方法 #includ ...
- [转]JavaScript 的性能优化:加载和执行
原文链接:http://www.ibm.com/developerworks/cn/web/1308_caiys_jsload/index.html?ca=drs- JavaScript 的性能优化: ...
- Windows下PhpStorm结合WAMP开发Phalcon应用的配置
最近要利用Phalcon框架开发PHP应用,因为以前基本没接触过PHP更没用过PHP框架,结果整环境整IDE配置什么的花了好长时间 学习慕课网上的PHP入门教程安装了WAMP(windows+apac ...
- HDU 5317 RGCDQ (质数筛法,序列)
题意:从1~1000,000的每个自然数质因子分解,不同因子的个数作为其f 值,比如12=2*2*3,则f(12)=2.将100万个数转成他们的f值后变成新的序列seq.接下来T个例子,每个例子一个询 ...
- scala学习笔记(9):Scala函数(2)
1 指令式编程&函数式编程 指令式:imperative 风格编程.指令式风格,是你常常使用像 Java,C++和 C 这些语言里用的风格,一次性发出一个指令式的命令,用循环去枚举,并经常改变 ...
- MYSQL复制的几种模式
MySQL 5.1 中,在复制方面的改进就是引进了新的复制技术:基于行的复制. MYSQL复制的几种模式 MySQL 5.1 中,在复制方面的改进就是引进了新的复制技术:基于行的复制.简言之,这种新技 ...
- 【解题报告】PKU 2318 TOYS AND PKU 2398 Toy Storage
题目连接: http://poj.org/problem?id=2318 http://poj.org/problem?id=2398 两题类似的题目,2398是2318的升级版. 题目大概是 ...
- UIPanGestureRecognizer中translationInView的理解
原因是在破船大牛的blog上面看到了一个demo #import <UIKit/UIKit.h> @interface ViewController : UIViewController ...