以下代码的输出让我感到惊讶。我的期望是
Inner
会将 num1
初始化为 10(事实上),然后 num2
将被初始化,复制 num1
的值 10。因此输出将是 10 10
。相反,我得到10 4
。
#include <iostream>
struct Inner {
uint64_t num1{10};
uint64_t num2{num1};
};
struct Outer {
uint64_t a{};
Inner inner{};
};
Outer makeOuter() {
return {.a = 4};
}
int main(int argc, char* argv[]) {
auto outer = makeOuter();
std::cout << outer.inner.num1 << " " << outer.inner.num2 << std::endl;
return 0;
}
num2
似乎复制了未初始化的内存(或者来自错误的地址?)。它接收 Outer
的成员 a
的值,无论该值是 4 还是 0xFFFFFFFFFFFFFFFF。
编译器是MSVC 19.37.32825.0。例如通过运行
cl main.cpp /std:c++latest /EHsc /O2 /link /out:program.exe
进行编译。
使用 clang++ 或 g++,我得到了预期的结果,
10 10
。编译器错误还是我的误解?
其他一些变化的影响:
Inner() {}
添加构造函数 Inner
-> 输出变为 10 10
Inner inner{}
更改为 Inner inner{11, 12}
-> 输出变为 11 12
(预期)Inner inner{}
更改为 Inner inner{11}
-> 输出变为 11 4
{}
而不是 {.a = 4}
-> 输出变为 10 10
Inner inner{}
中创建 main
并打印其成员 -> 输出变为 10 10
这是一个编译器错误。
makeOuter()
翻译为
Outer makeOuter(void) PROC ; makeOuter, COMDAT
mov eax, DWORD PTR __$ReturnAddress$[esp-4]
mov DWORD PTR [eax], 4
mov DWORD PTR [eax+4], 0
mov DWORD PTR [eax+8], 10 ; 0000000aH
mov DWORD PTR [eax+12], 0
mov DWORD PTR [eax+16], 4 ; <-- HERE
mov DWORD PTR [eax+20], 0
ret 0
Outer makeOuter(void) ENDP ; makeOuter
如果改变了
Outer makeOuter() {
return {.a = 4, .inner = {}};
}
然后翻译成
Outer makeOuter(void) PROC ; makeOuter, COMDAT
mov eax, DWORD PTR __$ReturnAddress$[esp-4]
mov DWORD PTR [eax], 4
mov DWORD PTR [eax+4], 0
mov DWORD PTR [eax+8], 10 ; 0000000aH
mov DWORD PTR [eax+12], 0
mov DWORD PTR [eax+16], 10 ; 0000000aH
mov DWORD PTR [eax+20], 0
ret 0
Outer makeOuter(void) ENDP ; makeOuter