为啥从 constexpr 引用生成的汇编代码与 constexpr 指针不同?
Posted
技术标签:
【中文标题】为啥从 constexpr 引用生成的汇编代码与 constexpr 指针不同?【英文标题】:Why is different assembly code generated from a constexpr reference than a constexpr pointer?为什么从 constexpr 引用生成的汇编代码与 constexpr 指针不同? 【发布时间】:2020-09-08 07:17:22 【问题描述】:我用 MSVC /O2
和 clang 编译了以下程序:
int i;
constexpr int& ir = i;
constexpr int* ip = &i;
int main()
ir = 1;
*ip = 2;
MSVC /O2 clang
=========================== =============================================
int i DD 01H DUP (?) ; i i:
_DATA SEGMENT .long 0 # 0x0
int & ir DQ FLAT:int i ; ir
_DATA ENDS ir:
.quad i
两个编译器都从ir
生成汇编代码,但不是从ip
生成的(上面省略了main
的代码)。请参阅godbolt。为什么ir
和ip
不同?我了解到,汇编代码中的引用和指针是相同的。
Gcc 做了一件更奇怪的事情。我用 gcc -O0
和 -O2
编译了以下程序:
int i;
constexpr int& ir1 = i;
constexpr int* ir1p1 = &i;
constexpr int& ir2 = i;
constexpr int* ir2p1 = &i;
constexpr int* ir2p2 = &i;
constexpr int& ir3 = i;
constexpr int* ir3p1 = &i;
constexpr int* ir3p2 = &i;
constexpr int* ir3p3 = &i;
gcc -O0 gcc -O2
========= ==================
i: ir3:
.zero 4 .quad i
ir1: ir2:
.quad i .quad i
.quad i ir1:
ir2: .quad i
.quad i i:
.quad i .zero 4
.quad i
ir3:
.quad i
.quad i
.quad i
.quad i
有了-O0
,为什么引用变量下面会有几个.quad i
?
-O2
代码是从引用生成的,而不是从指针生成的。为什么会有这种差异?请参阅godbolt。
【问题讨论】:
你为什么期望相同的代码?你认为指针和引用是一回事吗? @StephenM.Webb:我认为也有相似之处和不同之处,但在汇编代码中我从未看到它们之间有任何区别。因此,问题出现了:当前的差异是必要的还是只是在更复杂的实现中的疏忽? 不同的编译器生成不同的代码; 11 点的新闻。如果有多种方法可以生成导致相同结果的代码,C++ 标准将其留给实现来选择一种。对于将生成哪些实际指令,您没有保证,只有它们将实现原始源指定的行为(当然,除非存在未定义的行为,那么所有的赌注都没有了)。 在我看来,这确实像是编译器优化失败。可能是因为 constexpr 引用并没有真正意义,而且应该很少见。 "使用 -O0 为什么引用变量下有几个 .quad i ?" - 也许它使调试器更容易?毕竟,这是-O0
最关心的问题。
【参考方案1】:
除了指令问题,这只是链接:constexpr
暗示const
(在变量本身上,而不是在其所指对象上,如果有的话),从而将internal linkage 提供给您的指针。 (这是一个 hack,允许在 C++17 的内联变量之前的头文件中使用命名空间范围命名的常量;不幸的是,我们现在必须记住它。)由于没有其他翻译单元可以引用它们,因此无需发出符号;但是,这些引用可以在其他地方声明和使用:
extern int &ir;
void count() ++ir;
因此必须有一个符号来附加这些用途。
【讨论】:
extern int& ir
没有链接到constexpr int& ir = i;
。我得到了未解决的外部符号。所以我认为,后者毕竟是有内在联系的。不能在其他翻译单元中使用。
@Dr.Gut:它works for me。
我很惊讶,它适用于 gcc。它不适用于 MSVC 和 clang。我不明白,为什么。
确实有效。当我切换编译器时,我忘记在编译中添加def.cc
。如何创建指向魔杖盒程序的链接?
@Dr.Gut:当你运行它时,一个共享链接会出现在输出窗口的正上方。以上是关于为啥从 constexpr 引用生成的汇编代码与 constexpr 指针不同?的主要内容,如果未能解决你的问题,请参考以下文章
为啥我不能使用 constexpr 全局变量来初始化 constexpr 引用类型?
为啥 Solaris 汇编器生成的机器代码与这里的 GNU 汇编器不同?
为啥包装在函数中的 GAS 内联汇编为调用者生成的指令与纯汇编函数不同