我什么时候能确定constexpr全局变量会被"遗忘",就像C宏一样?

ein*_*ica 2 c++ macros constexpr

我想使用全局constexpr变量:

constexpr int foo = 123;
Run Code Online (Sandbox Code Playgroud)

而不是C宏:

#define FOO (123)
Run Code Online (Sandbox Code Playgroud)

在我写的一些代码中.我希望保证相同的行为,从某种意义上说,它不会在运行时占用内存空间,也不会在编译的目标代码中可见/存在(也就是说,它的值将被用作直接的地方相关).

我可以得到这个保证吗?在某些条件下?当然,假设我不是想使用x的地址或任何这样有趣的业务.

Whi*_*TiM 5

我能得到这个保证吗?在某些条件下?当然,假设我不想使用 x 的地址或任何此类有趣的事情。

是的,编译器几乎总是会foo在编译时替换数字,而不需要额外的内存(请参阅)constexpr。几乎可以肯定,编译器只会foo您获取地址的情况下分配内存。

并且,从([expr.const])上的链接......我们看到一条注释:

注意:常量表达式可以在翻译过程中求值。

而且,就我所知的大多数 C++ 编译器而言,它们会在可能的情况下计算并折叠表达式。


使用gcc.godbolt.org,此代码(不获取地址foo)...

constexpr int foo = 123;
int x(){
    int b = 5 + foo;
    return b;
}
Run Code Online (Sandbox Code Playgroud)

如果没有优化标志,生成的代码是:

x():
        movl    $128, %eax
        ret
Run Code Online (Sandbox Code Playgroud)

=========================================

但是这段代码...(取地址foo

constexpr int foo = 123;
int x(){
    int b = 5 + reinterpret_cast<long>(&foo);
    return b;
}
Run Code Online (Sandbox Code Playgroud)

生成....

x():
        movq    foo, -8(%rsp)
        movl    foo, %eax
        addl    $5, %eax
        ret
foo:
        .long   123
Run Code Online (Sandbox Code Playgroud)

注意:为什么我使用may而不是 if will是因为 C++ 标准并不强制编译器这样做(但他们几乎肯定会这样做,有些人可以根据自己的特定限制不这样做)。


M.M*_*M.M 5

C++标准不保证在运行时占用内存空间或目标文件的内容.

constexpr int foo = 123;在命名空间范围意味着foo具有内部链接,并且在每个转换单元中该行是可见的,存在具有静态存储持续时间的对象,具有sizeof(int)字节.

如果程序的输出不依赖于存储是否实际存在,则允许编译器(但不是必需)优化此存储.(这称为as-if规则).

如果您有一个功能,可能无法优化存储的示例:

int const *bar() { return &foo; }
Run Code Online (Sandbox Code Playgroud)

在实践中:

  • 这是非常有可能,如果foo没有ODR使用的话,就不会在运行时占用内存.
  • 这是极有可能foo的名字将不会出现在目标文件,因为它有内在联系.