外部常量链接规范似乎被G忽略了++ 我有一个情况,用C++编译器构造C代码库,与此类似:

外部常量链接规范似乎被G忽略了++ 我有一个情况,用C++编译器构造C代码库,与此类似:,c++,linker,g++,name-mangling,C++,Linker,G++,Name Mangling,lib.h lib.c main.c …然后它被添加后是这样的: $ objdump -t lib.o | grep values 0000000000000000 g O .rodata 0000000000000008 values $ objdump -t main.o | grep values 0000000000000000 *UND* 0000000000000000 values 所以名称mangling被删除了,我们看到一个L变成了一个G,链

lib.h

lib.c

main.c

…然后它被添加后是这样的:

$ objdump -t lib.o | grep values
0000000000000000 g     O .rodata    0000000000000008 values

$ objdump -t main.o | grep values
0000000000000000         *UND*  0000000000000000 values
所以名称mangling被删除了,我们看到一个L变成了一个G,链接器不会抱怨值未定义

现在想象一下同样的情况,两个非常相似的文件以同样的方式修改:

tmp exttypes.h

a-lib.c

这是项目中仅有的两个Reb_To_RXT定义,Build clean。但它没有链接,当我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,名字被弄坏了。这并没有让简单得多的例子感到高兴。但我想知道,外星人每次出现都在上面,这怎么会发生。我相信这是一把冒烟的枪,这是正确的吗?而且通常不应该发生只声明为外部的东西不应该在任何地方有本地链接吗?

是的,正确

我正在编辑的文件是自动生成的,实际上被一个干净的文件破坏了,它在写下思考过程的中途被注意到。您在该特定头文件中看到的tmp应该是提示临时的,不要编辑,如果文件没有在您正在使用的编辑器中重新加载,则可能会令人困惑

完成了机构知识的思路:-是的,正确

我正在编辑的文件是自动生成的,实际上被一个干净的文件破坏了,它在写下思考过程的中途被注意到。您在该特定头文件中看到的tmp应该是提示临时的,不要编辑,如果文件没有在您正在使用的编辑器中重新加载,则可能会令人困惑


完成了机构知识的思路:-我搞不懂你问什么

但是

拥有

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

我搞不懂你问什么

但是

拥有

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语言,要让他们修改它可能是一场艰苦的战斗。但如果有人引用它是UB,甚至是C,那么我可能有更多的弹药…?:-/@在C++11中,还可以将数组声明为constexpr并初始化它。但是,定义一个全局对象两次违反了ODR,是即时的。@HostileFork:N869,我认为C99的最后一个草案,§6.9/5:外部定义是一个外部声明,也是一个函数或对象的定义。如果使用外部链接声明的标识符用于表达式中,而不是作为sizeof运算符操作数的一部分,则在整个程序中的某个地方,该标识符应有一个外部定义;否则,不得超过一个。后来有了一个标准,C11,但我无法想象如此基本的东西已经改变了。MSVC只实现C89而不是C99,但是C89……顺便说一下,内联是C++中的一个非常不同的兽。我不熟悉C的意思。我不确定你能不能用C来定义标题,我更喜欢一个原型,然后是一个单一的定义,当然,这就是我应该怎么做的。但是我正在修改的代码是其他人的C语言,要让他们修改它可能是一场艰苦的战斗。但如果有人引用它是UB,甚至是C,那么我可能有更多的弹药…?:-/@在C++11中,还可以将数组声明为constexpr并初始化它。但是,定义一个全局对象两次违反了ODR,是即时的。@HostileFork:N869,我认为C99的最后一个草案,§6.9/5:外部定义是一个外部声明,也是一个函数或对象的定义。如果使用外部链接声明的标识符用于表达式中,而不是作为sizeof运算符操作数的一部分,则在整个程序中的某个地方,该标识符应有一个外部定义;否则,将不存在m 不止一个。后来有了一个标准,C11,但我无法想象如此基本的东西已经改变了。MSVC只实现C89而不是C99,但是C89……顺便说一下,内联是C++中的一个非常不同的兽。我不熟悉C的意思。我不确定你能不能在C中定义标题。。。
extern int const values[2] = {1, 2};
extern int const values[2];
typedef int const Values[2];

inline Values& valuesRef()
{
    static Values   theValues = {1, 2};
    return theValues;
}

static Values& values = valuesRef();