设置程序基址固定:关闭程序基地址改变

在vs中编写代码如下:

#include <stdio.h>

int main()
{
int a = 5;
printf("a的内存地址是 %d", &a);
system("pause");
return 0;
}

编译生成程序,找到vs生成的Test.exe文件,我们双击运行Test.exe,发现变量a的内存地址是1703668,

然后不关闭这个程序,再双击运行Test.exe,发现又运行起来一个程序,显示a的内存地址是1703668。

如图:

很奇怪啊,第一次运行时申请的变量a的内存地址是1703668,再次运行Test.exe时,内存地址1703668不是已经被占用了吗,为什么第二个程序的变量a的内存地址还是1703668?

这说明C语言中,或者说所有的编程语言中使用的内存地址都不是真实的物理地址,而是虚拟地址。

虚拟地址:CPU启动保护模式后,程序运行在虚拟地址空间中。

PS:不是所有程序都运行在虚拟地址中。CPU启动时是运行在实模式下的,Bootloader以及内核在初始化页表之前并不使用虚拟地址,而是直接使用物理地址的。

如果CPU寄存器中的分页标志位被设置,那么执行内存操作的机器指令时,CPU(准确来说,是MMU,即Memory Management Unit,内存管理单元)会自动根据页目录和页表中的信息,把虚拟地址转换成物理地址,完成该指令。
比如 mov eax,[004227b8h] ,这是把地址004227b8h处的值赋给寄存器的汇编代码,004227b8这个地址就是虚拟址。CPU在执行这行代码时,发现寄存器中的分页标志位已经被设定,就自动完成虚拟地址到物理地址的转换,使用物理地址取出值,完成指令。对于Intel CPU 来说,分页标志位是寄存器CR0的第31位,为1表示使用分页,为0表示不使用分页。对于初始化之后的 Win2k 我们观察 CR0 ,发现第31位为1。表明Win2k是使用分页的。
 
由此可知,虽然我们每次运行Test.exe得到的a的内存地址都是一样的,但我们知道这是虚拟地址,每次运行时申请到的物理内存的地址肯定是不一样的。
 
更多虚拟地址的问题参考:https://baike.baidu.com/item/%E8%99%9A%E6%8B%9F%E5%9C%B0%E5%9D%80/1329947?fr=aladdin

C语言中使用的地址是真实的物理地址吗?的更多相关文章

  1. 如何使用JAVA语言抓取某个网页中的邮箱地址

    现实生活中咱们常常在浏览网页时看到自己需要的信息,但由于信息过于庞大而又不能逐个保存下来. 接下来,咱们就以获取邮箱地址为例,使用java语言抓取网页中的邮箱地址 实现思路如下: 1.使用Java.n ...

  2. Android For JNI(二)——C语言中的数据类型,输出,输入函数以及操作内存地址,内存修改器

    Android For JNI(二)--C语言中的数据类型,输出,输入函数以及操作内存地址,内存修改器 当我们把Hello World写完之后,我们就可以迈入C的大门了,今天就来讲讲基本的一些数据类型 ...

  3. Swift语言中如何使用JSON数据教程

    这是一篇翻译文章,原文出处:http://www.raywenderlich.com/82706/working-with-json-in-swift-tutorial Swift语言中如何使用JSO ...

  4. C语言中不同变量的访问方式

    C语言中的变量大致可以分为全局变量,局部变量,堆变量和静态局部变量,这些不同的变量存储在不同的位置,有不同的生命周期.一般程序将内存分为数据段.代码段.栈段.堆段,这几类变量存储在不同的段中,造成了它 ...

  5. C语言中函数参数传递

    C语言中函数参数传递的三种方式 (1)值传递,就是把你的变量的值传递给函数的形式参数,实际就是用变量的值来新生成一个形式参数,因而在函数里对形参的改变不会影响到函数外的变量的值.(2)地址传递,就是把 ...

  6. Java语言中的面向对象特性总结

    Java语言中的面向对象特性 (总结得不错) [课前思考]  1. 什么是对象?什么是类?什么是包?什么是接口?什么是内部类?  2. 面向对象编程的特性有哪三个?它们各自又有哪些特性?  3. 你知 ...

  7. 在C语言中利用PCRE实现正则表达式

    1. PCRE简介 2. 正则表达式定义 3. PCRE正则表达式的定义 4. PCRE的函数简介 5. 使用PCRE在C语言中实现正则表达式的解析 6. PCRE函数在C语言中的使用小例子 1. P ...

  8. C语言中的栈和堆

    原文出处<http://blog.csdn.net/xiayufeng520/article/details/45956305#t0> 栈内存由编译器分配和释放,堆内存由程序分配和释放. ...

  9. JS 中没有按地址(引用)传递,只有按值传递

    很多人,包括我,受书本知识消化不彻底的影响,认为 JS 中参数有两种传递方式:数字.字符串等按值传递:数组.对象等按地址(引用)传递.对此种观点,我们要谨慎. var v1 = [] var v2 = ...

随机推荐

  1. 在matlab中实现梯度下降法

    梯度下降法的原理,本文不再描述,请参阅其它资料. 梯度下降法函数function [k ender]=steepest(f,x,e),需要三个参数f.x和e,其中f为目标函数,x为初始点,e为终止误差 ...

  2. scala中的一些特殊符号的意义

    1.作为“通配符”,类似Java中的*.如import scala.math._ 2.:_*作为一个整体,告诉编译器你希望将某个参数当作参数序列处理!例如val s = sum(1 to 5:_*)就 ...

  3. (转)Python3.5 queue模块详解

    原文:https://www.cnblogs.com/CongZhang/p/5274486.html queue介绍 queue是python中的标准库,俗称队列,可以直接import 引用,在py ...

  4. Linux下dmesg命令处理故障和收集系统信息的7种用法

    目录: <syslog之一:Linux syslog日志系统详解> <syslog之二:syslog协议及rsyslog服务全解析> <syslog之三:建立Window ...

  5. Redis随笔(五)Jedis、jedisCluster的使用

    1.Jedis客户端 https://redis.io/clients 2.Jedis源码包与使用介绍 https://github.com/xetorthio/jedis 3.项目中使用 通过mav ...

  6. ThreadPoolExecutor策略配置以及应用场景

    ThreadPoolExecutor 是用来处理异步任务的一个接口,可以将其理解成为一个线程池和一个任务队列,提交到 ExecutorService 对象的任务会被放入任务队或者直接被线程池中的线程执 ...

  7. ES6箭头函数this指向

    普通函数中的this: 1. this总是代表它的直接调用者(js的this是执行上下文), 例如 obj.func ,那么func中的this就是obj 2.在默认情况(非严格模式下,未使用 'us ...

  8. mysql笔记-索引

    什么是聚簇索引 聚簇索引:索引的叶节点就是数据节点(索引值).而非聚簇索引的叶节点仍然是索引节点(告诉你怎么在表中查找这一记录),只不过有一个指针指向对应的数据块. Innodb和MyIsam区别 转 ...

  9. tensorflow 在同一个GPU同时加载多张相同的图

    saver = self.tf_instance.train.Saver() self.sess = self.tf_instance.Session(config=sess_config, grap ...

  10. gson和fastjson

    实体类转string的时候gson会对 & 进行url编码; fastjson不会