未定义对 `__gxx_personality_sj0` 的引用

23

使用gcc 4.6时,尝试执行以下代码:

   #include <iostream>

using namespace std;

#include <bitset>

int main()
{
   //Int<> a;
   long long min = std::numeric_limits<int>::min();
   unsigned long long max = std::numeric_limits<int>::max();
   cout << "min: " << min << '\n';
   cout << "max: " << max << '\n';
   cout << (min <= max);
   std::bitset<64> minimal(min);
   cout << "minimal: " << minimal;

   return 0;
}

我遇到了以下错误:
1. __gxx_personality_sj 未定义引用
2. _Unwind_SjLj_Register 未定义引用
3. _Unwind_SjLj_Unregister 未定义引用
4. _Unwind_SjLj_Resume 未定义引用

到底是怎么回事?!


请发表一个完整的示例,以便我们可以将其提供给编译器以重现错误。请参阅http://sscce.org。 - Björn Pollex
1
@Mystical:这是一个链接错误。在解析期间,C编译器会发出警告。 - Björn Pollex
这段代码无法编译,你需要添加 #include <limits> - Björn Pollex
非常类似于这个问题:https://dev59.com/QUvSa4cB1Zd3GeqPgrvR - ks1322
GCC 4.3.4 可以很好地编译、链接和运行这个程序链接 - Björn Pollex
5个回答

31

这些函数是GCC中的C++异常处理支持的一部分。GCC支持两种异常处理方式,一种基于调用setjmp和longjmp(sjlj异常处理),另一种基于DWARF调试信息格式(DW2异常处理)。

如果您尝试在一个可执行文件中混合编译使用不同异常处理实现的对象,则会出现这些链接器错误。看起来您正在使用DW2 GCC,但您尝试使用的某个库是使用sjlj版本的GCC编译的,导致了这些错误。

简短的回答是,这些问题是由不同编译器之间的ABI不兼容性引起的,因此当您混合使用使用不同编译器编译的库或使用不兼容的同一编译器版本时,就会出现这些问题。


11
我修复了那个问题。我的问题在于工具链中编译器我使用的是i686-pc-mingw32-gcc-4.6.0.exe,但链接器我使用的是mingw32-g++.exe。我将其更改为i686-pc-mingw32-g++.exe,问题已解决。谢谢。 - smallB
2
@smallB 如果这个答案解决了你的问题,你应该接受它! - Alex
@Alex,除了这个答案并没有解决问题。OP的错误是根本没有链接到libstdc++,而不是链接到不兼容的库。 - Jonathan Wakely
3
请您阅读小B的评论,他说gcc被用作编译器,而g++被用作链接器,根据您的解释,这应该已经链接了libstdc++。小B还提到,将g++版本切换为i686版本后,“问题得到解决”。请JonathanWakely重新阅读一下这条评论。 - Alex
好的答案,解决了我的问题。我使用的是CodeBlocks安装的mingw-g++,而不是我自己安装的那个 :D - Javid
2
尽管这个答案不是针对原始问题的,但它可以帮助那些遇到相同错误的人。在我的情况下,我在Ubuntu 14上构建了一个存档库,并尝试将其链接到在Windows上运行mingw-w64编译器的seh版本。在Windows上安装mingw-64时,您可以选择下载seh或sjlj版本。但是当您使用apt-get在Ubuntu上安装它时,您会得到存储库中的版本。Ubuntu 14配置为sjlj版本,而Ubuntu 16则具有seh版本。 - nmgeek

12

正如小B在评论中指出的那样,您可能使用了gcc,专注于C程序,但是您有一个C++程序。

要编译C++程序,请确保使用g++编译器驱动程序!

例如:

错误: gcc -o foo.exe foo.cpp

正确: g++-o foo.exe foo.cpp


2
不太准确,gcc 只是运行正确编译器的驱动程序,对于 .cpp 或者 .cc 文件,它将会运行 C++ 编译器。但与 g++ 驱动程序不同的是,gcc 不会自动链接到 C++ 标准库。当然,在手册中有记录。https://gcc.gnu.org/onlinedocs/gcc/Invoking-G_002b_002b.html - Jonathan Wakely
@JonathanWakely非常有见地,我喜欢你的评论!对像我这样的“C”小白来说,是一种温柔的触摸。我已经更新了我的答案,以使其更准确。我故意保持简单。至于琐事,文档中大约有288715个单词 - 显然!;) - n611x007

9
< p >如果其他人也遇到了这个问题:我在创建项目的.o文件后更改了编译器。

当我重建同样的项目时,新编译器没有生成新的.o文件,因此它们缺少一些关键信息。删除旧文件并重新构建后,错误被修复。

我认为如果从头开始重建而不进行删除,结果应该是相同的。


1
这个答案被严重低估了,解决了所有那些在疯狂搜索后找不到引用的问题。 - George Menoutis

3
gcc命令只是一个驱动程序,它会为您提供的源文件运行正确的编译器(或者如果您提供的是目标文件,则运行链接器)。对于已知文件扩展名的C++源文件,它将运行C++编译器(对于GCC而言,称为cc1plus),并正确地编译代码。 但是它不会自动链接到C++标准库(对于GCC而言,叫做libstdc++)。
要解决这个问题,您需要在链接时显式地链接到该库,方法是添加-lstdc++选项,或者使用g++驱动程序进行编译和链接,它会自动将-lstdc++添加到链接器选项中。
因此,您可以使用gcc来编译C++程序,但如果您使用任何标准库或C++运行时的特性(包括异常处理),则需要使用-lstdc++(或者只使用运行时的-lsupc++)来链接C++运行时。使用g++会自动完成这些操作。
这在手册中有详细说明:https://gcc.gnu.org/onlinedocs/gcc/Invoking-G_002b_002b.html

1
没错,这解决了问题。问题并不在于“SLJL和DWARF不匹配”,而是将C程序链接到一些C++库,因此添加-lstdc++就解决了问题。谢谢!同样,请确保它在其他需要它的库“之后”运行,并确保确切的命令包含它 :) - rogerdpack

0

使用minGW-g++.exe而不是gcc.exe,看看现在会发生什么。


为什么这个答案比8年前的更好?它也提到了mingw编译器。 - stdunbar

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接