我有一种情况是使用 C++ 编译器构建 C 代码库,与此类似:
lib.h
extern int const values[2] = {1, 2};
lib.c
#include "lib.h"
main.c
#include <iostream>
extern int const values[2];
int main() {
std::cout << values[0] << ":" << values[1] << std::endl;
}
由于 C++03 Standard Annex C Compatibility C.1.2 Clause 3 中指出的某些内容,我不得不添加 extern . (使用 -fpermissive
编译会将其隐藏起来。)
顺便说一句,values
在 objdump 中的显示方式与 extern
之前的区别如下:
$ objdump -t lib.o | grep values
0000000000000000 l O .rodata 0000000000000008 _ZL6values
$ objdump -t main.o | grep values
0000000000000000 *UND* 0000000000000000 values
...然后添加之后是这样的:
$ objdump -t lib.o | grep values
0000000000000000 g O .rodata 0000000000000008 values
$ objdump -t main.o | grep values
0000000000000000 *UND* 0000000000000000 values
因此名称重整被删除了,我们看到“L”变成了“G”,并且链接器不会提示 values
未定义。
现在想象同样的情况,有两个非常相似的文件,以相同的方式修改:
tmp-exttypes.h
extern const REBYTE Reb_To_RXT[REB_MAX] = { /* bunch of stuff */ };
a-lib.c
extern const REBYTE Reb_To_RXT[REB_MAX];
这是项目中仅有的两个 Reb_To_RXT 定义,构建干净。但它没有链接,当我 objdump 只有两个提到它的文件时,我得到:
$ objdump -t a-lib.o | grep Reb_To_RXT
00000000 *UND* 00000000 Reb_To_RXT
$ objdump -t f-extension.o | grep Reb_To_RXT
00000080 l O .rodata 00000038 _ZL10Reb_To_RXT
它说 L,它的名字被破坏了。这并没有让这个简单得多的例子开心。但是我想知道在每次出现时外部如何发生这种情况。我是否正确地相信这是确凿的证据……通常不应该发生仅声明为外部的东西在任何地方都不应该有本地链接吗?
最佳答案
我无法理解你问的问题。
但是……
有
extern int const values[2] = {1, 2};
在头文件中,如果该头文件包含在多个翻译单元中,则您有 UB。很可能但不一定会出现链接错误。
一个解决方案:在头部声明数组,比如
extern int const values[2];
但在实现文件中定义它(使用初始化程序)。
另一种解决方案是使用模板技巧或内联函数技巧在头文件中定义数组。
内联函数技巧:
typedef int const Values[2];
inline Values& valuesRef()
{
static Values theValues = {1, 2};
return theValues;
}
static Values& values = valuesRef();
关于c++ - extern const 链接规范似乎被 G++ 忽略,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/13908376/