C++ 在编译过程中就可以获得变量的地址?

今天在阅读C++ Primer "constexrp和常量表达式"章节时发现有这么一句话:

"常量表达式是指值不会改变并且在编译过程就能得到计算结果的表达式"

又有:

"C++11标准新规定, 允许将变量声明为constexpr来由编译器验证变量的值是否是一个常量表达式"

在验证constexpr类型说明符功能时我编写了如下代码:

#include <iostream>

int a = 99;

constexpr int *pa = &a;

int main()
{
    std::cout<<pa<<std::endl;

    return 0;
}

这段代码编译通过了并输出了结果;

我的疑问是, 按我一直以来的理解, 程序中的数据是在运行时才会被加载到内存中的,这里a应该是放在了全局/静态存储区;
而这里constexpr int *pa = &a;通过了编译,说明&a是一个可以在编译过程中获得结果的常量表达式, 所以说这里C++编译器在编译过程中就得到了&a的计算结果即a的地址?

阅读 7k
7 个回答

没用过C++ 但是编译器在编译过程就会把变量的地址确定下来
而局部变量不一样 它是放在栈中的 地址在运行中才会确定下来
举个例子:
假如我编译一门语言 在内存中分配了一块内存供变量使用 假设地址从0开始算 遇到一个新变量 地址标为0 并记录在哈希表中 再遇到一个新变量地址标为1 依此类推 并且用符号表记录下来 如果遇到的一个变量已经在哈希表中 那代表不是新变量

// 变量哈希表类似这样 值是内存地址
{
    a: 0,
    b: 1,
    c: 2
}

你的理解是正确的。全局变量就是这个特点。
如果放在main函数内部就会报错

prog.cc: In function 'int main()':
prog.cc:9:21: error: '& a' is not a constant expression
    9 | constexpr int *pa = &a;
      |  

这个a在编译的时候有个地址,它是相对地址,链接或者可执行文件加载到内存以后,要进行重定位,会进行改变。

C/C++中数据是在运行时加载到内存中的,但数据存放的位置也就是地址(准确地来说是地址的偏移量)是在编译期就确定好的。所以&a是一个编译期常量。

编译后的程序是没有变量名的,都是通过不同的寻址规则去访问,.net比较特殊,我现在说说c怎么处理的,如果是函数中的静态变量、全局变量程序是直接用一个固定地址去访问的,也就是说如果代码里写了&a这种要获取变量a地址的代码并不需要什么额外计算,因为程序一开始就只知道a的地址(如果要访问a的值反而需要额外计算)

非常粗略地说,编译期知道的只是在可执行文件中的地址。执行时的内存是由可执行文件映射而成。

编译后的程序是没有变量名的

撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题