为什么每次运行程序时变量地址都会有特定的数量(例如" printf("%d%d \ n",& a,& b); "。它将在一次运行中打印" 1000 988"" 924 912"在另一个运行中," 1288 1276"等等等等) ?在每个变量声明后,编译器是否会占用一定量的内存而无法写入任何内容?如果是,它依赖于什么?在我的程序中使用一些变量,它们之间的最小差异是12个字节,它达到212.这是唯一一个差异不是十二的倍数的情况(在其他情况下它是24,36或48)字节)。那背后有什么理由吗?由于我的变量是int类型(在我的系统中占用4个字节),我的变量地址之间的差异是否可以小于12(例如4)?那些地址差异取决于变量类型吗?如果是,以什么方式?提前谢谢!
答案 0 :(得分:4)
今天大多数操作系统使用地址空间布局随机化,以便更难编写某些类型的恶意软件。 (将代码写入内存然后尝试让程序将控制交给它的那种;现在必须猜测要使程序跳转到哪个地址。)因此,变量不会在同一地址每次你运行一个程序。
根据变量的类型,分配方式以及运行的操作系统和体系结构,变量的大小和对齐方式会有所不同。编译器和运行时可能会或可能不会总是将它们放在四个,八个或十六个字节的边界上。例如,x86_64函数调用ABI总是在16字节边界上启动函数的堆栈帧,而malloc()
的某些实现总是返回可被16整除的地址,因为这需要在某些CPU上存储向量。
如果您想知道编译器正在做什么,您可以尝试编译汇编。在gcc或clang上,您可以使用-S
标志执行此操作。
答案 1 :(得分:2)
如果你问为什么变量的内存地址在不同的可执行运行之间有所不同,那么答案就是ASLR,这是为了更难以利用代码中的安全问题(参见https://en.wikipedia.org/wiki/Address_space_layout_randomization)。
如果禁用ASLR,每次运行可执行文件时,您将获得给定变量的相同地址。
答案 2 :(得分:0)
您的链接器(在某种程度上,您的编译器)列出了应用程序的地址空间。链接器通常基于某个地址(例如,零)构建可重定位图像。显然,您的加载程序在运行时将可重定位图像放在不同的位置。
在每个变量声明后,编译器是否会占用一定量的内存而无法写入任何内容?
通常没有UNLESS,下一个变量需要对齐。变量通常与地址相对应,该地址是变量大小的倍数。
听起来你的编译器正在为你根本不考虑的东西分配内存。