我有一种情况,用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
中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
的方式有何不同?
values
...然后在添加之后就像这样:
extern const REBYTE Reb_To_RXT[REB_MAX] = { /* bunch of stuff */ };
因此删除名称mangling,我们看到“L”变为“G”,并且链接器不会抱怨extern const REBYTE Reb_To_RXT[REB_MAX];
未定义。
现在想象两个非常相似的文件的相同情况,以相同的方式修改:
TMP-exttypes.h
$ 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
一个-lib.c
{{1}}
这是项目中唯一两个Reb_To_RXT定义,构建清晰。但它并没有链接,当我只提到我提到的两个文件时,我得到了:
{{1}}
它说L,它的名字被破坏了。这并没有让更简单的例子开心。但是我想知道如果每次出现它的外部都会发生这种情况。我是否正确地相信这是一支冒烟的枪......并且通常不应该发生只被宣布为外部的东西不应该在任何地方都有本地联系?
答案 0 :(得分:3)
我无法理解你问的问题。
但......
具有
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();
答案 1 :(得分:1)
是的,没错。
你(我)正在编辑的文件是自动生成的,并且实际上被一个干净的make破坏了,在写下思考过程的过程中注意到了这一点。您在该特定标题中看到的“tmp”应该暗示“临时,不要编辑”,如果文件没有在编辑器中重新加载,那么您使用它可能会让人感到困惑。
(无论如何为机构知识完成了思路。:-P)