我什么时候可以确定一个 constexpr 全局变量会像 C 宏一样被"forgotten"?

When can I be sure a constexpr global variable will be "forgotten", like a C macro?

本文关键字:一样 forgotten constexpr 什么时候 一个 全局变量      更新时间:2023-10-16

我想使用全局constexpr变量:

constexpr int foo = 123;

而不是 C 宏:

#define FOO (123)

在我正在编写的某些代码中。我希望得到相同的行为保证,从某种意义上说,这不会在运行时占用内存空间,也不会在编译的目标代码中可见/存在(也就是说,它的值将用作相关的即时值(。

我能得到这个保证吗?在某些条件下?当然,假设我没有试图使用x的地址或任何此类有趣的业务。

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

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

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

存储可能不会

优化的一个例子是,如果你有一个函数:

int const *bar() { return &foo; }

在实践中:

  • 如果foo不是ODR使用的,那么它很可能在运行时不会占用内存。
  • foo 的名称很可能不会出现在目标文件中,因为它具有内部链接。

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

是的,编译器几乎总是在编译时用foo替换数字,没有额外的内存 请参阅constexpr 。几乎可以肯定的是,编译器只会在获取foo地址时为其分配内存。

而且,从链接([expr.const](...我们看到一个注释:

注: 常量表达式可以在翻译过程中计算。

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


使用 gcc.godbolt.org,此代码(不采用foo的地址(...

constexpr int foo = 123;
int x(){
    int b = 5 + foo;
    return b;
}

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

x():
        movl    $128, %eax
        ret

====

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

但是这个代码...(以foo地址为准(

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

生成。。。。

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

注意:为什么我使用可能而不是如果意志是因为C++标准不会强迫编译器这样做,(但他们几乎肯定会这样做,有些人可以自由地不这样做他们的特定约束(。

我希望得到相同的行为保证,从某种意义上说,这不会在运行时占用内存空间,也不会在编译的目标代码中可见/存在(也就是说,它的值将用作相关的即时值(。

constexpr int foo = 123;

每当编译器点击它时,将同样被视为123。没有额外的记忆,没有什么花哨的。

所以是的,它完全等同于预处理器的替代品

#define FOO (123)