内存中的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规定其为静态存储方式, 每次调用的初始值为上一次调用的值,调 ...
随机推荐
- c#获取机器唯一识别码
前言 在客户端认证的过程中,我们总要获取客户机的唯一识别信息,曾经以为MAC地址是不会变的,但是现在各种改,特别是使用无线上网卡,MAC地址插一次变一次,所以这样使用MAC就没有什么意义了,怎么办,又 ...
- hdu 5067 Harry And Dig Machine (状态压缩dp)
题目链接 bc上的一道题,刚开始想用这个方法做的,因为刚刚做了一个类似的题,但是想到这只是bc的第二题, 以为用bfs水一下就过去了,结果MLE了,因为bfs的队列里的状态太多了,耗内存太厉害. 题意 ...
- npm使用过程中的一些错误解决办法及npm常用命令
node,npm在前端开发流程中提供了非常完善的自动化工具链,但是同样由于其复杂性导致有很多奇奇怪怪的问题.本文将记录使用过程中出现的一些问题及其解决方法备案. 国内由于gfw问题,导致很多国外的网站 ...
- UVa 10020 (最小区间覆盖) Minimal coverage
题意: 数轴上有n个闭区间[ai, bi],选择尽量少的区间覆盖一条指定线段[0, m] 算法: [start, end]为已经覆盖到的区间 这是一道贪心 把各个区间先按照左端点从小到大排序,更新st ...
- UVa 11039 (排序+贪心) Building designing
白书上的例题比较难,认真理解样例代码有助于提高自己 后面的练习题相对简单,独立思考解决问题,增强信心 题意:n个绝对值各不相同的非0整数,选出尽量多的数排成序列,使得该序列正负交错且绝对值递增. 解法 ...
- UIView的user Interaction Enabled属性
A Boolean value that determines whether user events are ignored and removed from the event queue. 译: ...
- gcc g++ 参数介绍
C和C++ 编译器是集成的.他们都要用四个步骤中的一个或多个处理输入文件: 预处理 (preprocessing),编译(compilation),汇编(assembly)和连接(linking).源 ...
- IOS中字符串操作
1.比较大小 - (NSComparisonResult)compare:(NSString *)string; 返回值NSComparisonResult有3种情况: NSOrderedAscend ...
- (六)6.7 Neurons Networks whitening
PCA的过程结束后,还有一个与之相关的预处理步骤,白化(whitening) 对于输入数据之间有很强的相关性,所以用于训练数据是有很大冗余的,白化的作用就是降低输入数据的冗余,通过白化可以达到(1)降 ...
- 【转】U-boot分析与移植(1)----bootloader分析
原文网址:http://blog.csdn.net/jianchi88/article/details/7061089 一.Boot Loader 概念 就是在操作系统内核运行之前运行的一段小程序. ...