返回信息流```c++
// foo.cpp
extern constexpr int g_z{3};
```
```c++
// main.cpp
#include <iostream>
extern int g_z;
int main()
{
std::cout << g_z << '\n';
++g_z;
std::cout << g_z << '\n';
return 0;
}
```
```bash
# 编译指令
g++ main.cpp foo.cpp -std=c++17
```
问题:为什么编译链接不报错,非要等到执行到
`++g_z` 这一句才蹦出个错误出来:
```
terminated by signal SIGBUS (Misaligned address error)
```
这是一条镜像帖。来源:北邮人论坛 / cpp / #101949同步于 2022/5/25
该镜像源已超过 30 天没有更新,可能在源站已被删除。
CPP机器人发帖
【问题】extern constexpr 问题
YiYeShu
2022/5/25镜像同步5 回复
订阅后,新回复会通过你的通知中心匿名送达。
5 条回复
我刚也试了下, gcc 11.2的行为和楼主一样; 但是用msvc 就过不了编译,提示没找到符号, 然后我就分别dump了g++和msvc生成的foo.cc的obj文件, 发现g++生成的符号虽然在rodata区, 但是并没有const约束, 而msvc生成的符号是有const约束的...不知道是不是这个导致的, 求问大神
首先,++g_z这一行当然是有问题的,因为它是一个const变量,编译器会把它放在只读的数据段中。对只读的数据段进行写入当然会触发 memory access violation。
然后问题:为什么编译链接不报错,非要等到执行到++g_z 这一句才蹦出个错误出来
两个直接原因:
1. 这个问题无法被编译器发现,因为编译器只对当前文件进行编译,看不到其它文件,因此也无法得知 g_z 的定义
2. 编译器的 name mangling 产生的符号不携带类型,因此链接器(ld)也无法发现这个问题
可以用以下命令查看 foo.cpp 输出的符号:
pyth0n@precision3630tower /tmp $ gcc -c foo.cc -o foo.o
pyth0n@precision3630tower /tmp $ nm -a foo.o
0000000000000000 a foo.cc
0000000000000000 R g_z
从上文可以看出,foo.cpp导出的符号为 g_z,没有携带 constexpr int 类型,因此链接器无法发现
所以,更进一步地,即使两个文件声明的变量类型完全不一样,编译也能通过,只是结果不是想要的而已。例如:
// foo.cpp
extern int g_z;
int g_z = 3;
// main.cpp
#include <iostream>
extern double g_z; // NOTE: should be `extern int g_z` here
int main()
{
std::cout << g_z << '\n'; // OUTPUT: 1.4822e-323
++g_z;
std::cout << g_z << '\n'; // OUTPUT: 1
return 0;
}
好的,多谢
【 在 pyth0n 的大作中提到: 】
: 首先,++g_z这一行当然是有问题的,因为它是一个const变量,编译器会把它放在只读的数据段中。对只读的数据段进行写入当然会触发 memory access violation。
:
: 然后问题:为什么编译链接不报错,非要等到执行到++g_z 这一句才蹦出个错误出来
: ...................
不同的编译器,结果不一样,这种事太烦了,[em21]
【 在 markovwang 的大作中提到: 】
: 我刚也试了下, gcc 11.2的行为和楼主一样; 但是用msvc 就过不了编译,提示没找到符号, 然后我就分别dump了g++和msvc生成的foo.cc的obj文件, 发现g++生成的符号虽然在rodata区, 但是并没有const约束, 而msvc生成的符号是有const约束的...不知道是不是这个导致的, 求问大神