C++ g++;无法将.o文件链接到可执行文件中
我正在用课本上的一个示例练习来学习。我只需要编译、链接和运行以下3个文件:C++ g++;无法将.o文件链接到可执行文件中,c++,linker,g++,clang,linker-errors,C++,Linker,G++,Clang,Linker Errors,我正在用课本上的一个示例练习来学习。我只需要编译、链接和运行以下3个文件: //file my.h extern int foo; void print_foo(); void print(int); h是一个简单的头文件,它声明了两个函数和一个“全局”int foo,没有初始值 //file my.cpp #include "my.h" #include "std_lib_facilities.h" //not included but not source of error void p
//file my.h
extern int foo;
void print_foo();
void print(int);
h是一个简单的头文件,它声明了两个函数和一个“全局”int foo,没有初始值
//file my.cpp
#include "my.h"
#include "std_lib_facilities.h" //not included but not source of error
void print_foo()
{
cout << foo << endl;
}
void print(int i)
{
cout << i << endl;
}
它创建了两个对象文件my.o和use.o。我使用以下命令链接它们:
g++ -o myprog my.o use.o
告诉我这个错误:
Undefined symbols for architecture x86_64:
"_foo", referenced from:
print_foo() in my.o
_main in use.o
(maybe you meant: __Z9print_foov)
ld: symbol(s) not found for architecture x86_64
clang: error: linker command failed with exit code 1 (use -v to see invocation)
我试过把
int foo;
进入我的.h而不是
extern int foo;
这给了我同样的错误
我试过使用
-std=c++11
导致相同错误的标志
我正在使用MacBook Pro和最新的macOS(事实上刚刚更新),如果这有助于解释错误消息的话
我尝试初始化foo,但没有改变任何东西
另外,我尝试过更新命令行工具,同样的错误
据我所知,错误告诉我,即使my.h包含在这两个文件中,也没有人可以使用foo变量(它调用_foo)实现任何函数,尽管它在my.h中显式声明。我的猜测是链接器在引擎盖下使用了错误的名称,这使得链接到可执行文件是不可能的。这是因为错误中提到了
__Z9print_foov
在任何文件中都不存在
在这一点上,它几乎像是一个g++或macOS/命令行工具错误。我不想每次都添加声明,因为这样会产生重复的符号错误。将my.cpp和use.cpp放在一个文件中可能会正确链接,但我需要确保我可以实际链接多个cpp文件,因为我最终(希望)将使用需要链接的多个cpp文件。感谢您的帮助 我建议用两个命令编译g++-Wall-cmy.cpp
(即给出一个my.o
)和g++-Wall-c use.cpp
(给出use.o
),然后将程序链接到g++my.o use.o-o myprog
。实际上,您应该编写一个(请参阅以获取灵感)并简单地运行make
您的翻译单元my.cpp
和use.cpp
都在声明一些extern-int-foo代码>从未定义的变量。因此,您需要在一个文件中定义它(但不能在其他文件中!),例如,可能需要单独添加(到my.cpp
)
(没有extern
)或者甚至有一些明确的初始值,例如intfoo=34代码>
这是因为错误提到了一个不存在的\uuuuz9print\ufoov
它是一个,在两个对象文件中都引用(但未定义)(另请参见)
在这一点上,它几乎像是一个g++或macOS/命令行工具错误
您不太可能在编译器工具中发现bug(这两个工具都经过了非常好的测试;因为它们都是数百万行的自由软件,它们确实存在残余bug,但是您赢得彩票的机会比受到编译器bug影响的机会要多)。我从1974年开始编写代码,这在我一生中只发生过一次。更现实的态度是更谦虚,在怀疑编译器或构建链之前,先对自己的代码(和知识)提出质疑
顺便说一句,总是先编译所有警告和调试信息(例如g++-Wall-g
,也可能-Wextra
)。使用gdb
调试器。当您确信您的代码没有bug时,您可以通过要求编译器对其进行基准测试(因此使用g++-Wall-O2
也可以使用-g
进行编译)
请阅读维基页面。深入您的(另请参见和标准,例如草稿)了解声明和定义某些变量或函数之间的区别。通常,您会在一些公共标题(包含在几个翻译单元中)中声明一个全局extern
变量,并在其他地方定义一次,但最好的做法是避免使用大量全局变量。另请参见新变量 在此声明一个变量:
extern int foo;
cout << foo << endl;
然后使用变量:
extern int foo;
cout << foo << endl;
cout声明int-foo;在my.cpp中;成功了!谢谢你的帮助。但是,如果变量是在头文件中声明的,因此在包含它的.cpp文件中声明的(除非我遗漏了什么),我不理解链接器为什么会出现问题。如果要在.cpp文件中再次声明extern int foo,那么在头文件中声明extern int foo有什么意义?为了惯例?我不认为外星人有什么特别的,但仍然好奇,所以我没有这个问题了。阅读更多的C++书籍关于声明变量和定义之间的差异。bug的评论更多的是出于挫败感,而不是其他原因,并不打算破坏进入gcc的努力哈哈。我肯定会努力变得更谦虚。谢谢你花时间给我的建议不仅仅是回答问题!我阅读了一些文档,意识到即使没有任何初始化值,普通的int-foo也算作声明和定义,而头中的extern-int-foo是在没有定义的情况下声明的,因此没有定义,导致了我的错误代码>在标题中(包含在多个翻译单元中),并有一个.cpp
文件声明foo
。另请参见内联变量。
cout << foo << endl;