外部常量链接规范似乎被G++忽略了

extern const linkage specification being seemingly ignored by G++

本文关键字:G++ 范似乎 常量 链接 外部      更新时间:2023-10-16

我遇到了一种情况,用一个与之类似的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;
}

我不得不添加extern,因为C++03标准附录C兼容性C.1.2第3条中指出了一些问题。(使用-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_XT定义,构建得很干净。但它没有链接,当我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的东西在任何地方都不应该有本地链接,这通常不应该发生吗?

我搞不懂你问了什么。

但是…

具有

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();

是,正确。

你(我)正在编辑的文件是自动生成的,实际上是由一个干净的make销毁的,在写下思考过程的中途注意到了这一点。你在那个特定的标题中看到的"tmp"应该暗示"临时的,不要编辑",如果文件没有在你使用的编辑器中重新加载,这可能会让人困惑。

(完成了机构知识的思路。:-p)