【问题标题】:linking error: __thiscall function symbol not found but __cdecl function symbol is defined链接错误:__thiscall 函数符号未找到但 __cdecl 函数符号已定义
【发布时间】:2017-01-03 21:41:09
【问题描述】:

我正在尝试使用 Visual Studio 2012 编译一个测试程序,该程序应该链接到同事给我的 test.lib 文件。

编译在链接步骤停止并出现错误 LNK2019。缺少的符号是:

public: virtual __thiscall abc::Test::~Test(void)

使用实用程序dumpbin,我发现在 test.lib 中定义了以下符号:

public: virtual __cdecl abc::Test::~Test(void)

这两个函数有什么区别?我该如何解决这个编译问题?我是否缺少一些编译标志?

【问题讨论】:

  • 你定义了析构函数吗?
  • 您很可能使用不同的编译器选项编译您的测试程序,而不是您的同事编译他的库所使用的。调用约定的不同使我相信这一点。
  • @Raindrop7: 析构函数已定义
  • @PaulMcKenzie:你知道我应该检查哪些标志吗?
  • 不仅仅是编译器选项。任何可能打开/关闭特定调用约定的预处理器符号也会影响正在发生的事情。您需要与您的同事协调并非常仔细地比较他/她是如何构建库的,以及您是如何构建应用程序代码的。静态库只不过是打包在单个文件中的目标代码。但是,该目标代码必须与生成的目标代码基本相同,就好像您已获取库的源文件之一并在您的应用程序中自己构建它一样。显然情况并非如此。

标签: c++ visual-studio linker cmake


【解决方案1】:

你没有错过旗帜。

Calling convention modifiers,如__thiscall__cdecl,内部修改函数名。因此,__thiscall abc::Test::~Test(void)__cdecl abc::Test::~Test(void) 的功能不同。要解决此问题,请将 __thiscall 更改为 __cdecl

IIRC,__cdecl 是 MSVC(Visual Studio 的编译器)的默认调用约定,因此如果您的同事没有指定任何特殊内容,dumpbin 会将函数描述为具有__cdecl 调用约定。

说明:

与 C 不同,C++ 函数、方法和对象的内部名称​​不与源文件中的名称相同。这称为name mangling(有时称为名称装饰)。名称修饰允许函数重载,即具有几个仅在参数类型以及类/命名空间成员资格等方面不同的函数。

假设我有以下 C 程序:

// Foo.c
#include <stdio.h>

void myPrint(void) {
    printf("Hello, World!\n");
}

void myPrint(const char* str) {
    printf(str);
}

int main() {
    myPrint();
    myPrint("Hello, World!\n");
}

如果您尝试将其编译为 C 代码:

$ gcc -o Foo Foo.c
Foo.c:7:6: error: redefinition of ‘myPrint’

但如果你尝试将其编译为 C++:

$ g++ -o Foo Foo.c

它编译。

如果您尝试使用g++ -o Foo.s Foo.cpp -S -Os 查看程序集,您将看到void myPrint(void); 函数的重整名称为_Z7myPrintv(最后的v 代表void),而void myPrint(const char*); 函数的重整名称名称是_Z7myPrintPKcPKc:指向 Konstant 字符的指针)。

顺便说一下,函数名称的错位取决于您使用的编译器。使用 MSVC(Visual Studio 的编译器),void myPrint(const char*); 具有以下错误名称:?myPrint@@YAXPBD@Z

【讨论】:

  • 感谢您的解释。我现在的问题是我不知道如何将 __thiscall 更改为 __cdecl。我查看了代码,没有发现任何暗示使用 __thiscall 或 __cdecl 进行编译的内容。
  • 不要只看代码。查看代码生成选项。也许该库是使用不同的优化设置或其他设置编译的。您需要在 Visual Studio 中同时加载您的项目和库项目,并确保所有与代码生成相关的设置都相同。
  • @PaulMcKenzie - 在原始帖子中我没有提到我将 CMake 与 Visual Studio 11 生成器一起使用。我刚刚用 Scons 做了一个实验,它编译了(我小心地添加了 CMake 自动添加的所有定义和标志)!但是既然标志和定义是一样的,那还能是什么呢?我正在从同一个标准提示符运行这两个编译。
  • 我终于设法用 CMake 编译了。我没有使用 CMake 生成器“Visual Studio 11”,而是使用了生成器“Visual Studio 11 Win64”,一切正常。使用 C:/Program Files (x86)/Microsoft Visual Studio 11.0/VC/bin/cl.exeC:/Program Files (x86)/Microsoft Visual Studio 11.0/VC/bin/x86_amd64/cl.exe 时,Visual Studio 处理 __thiscall__cdecl 的方式有什么不同吗?
猜你喜欢
  • 2012-05-08
  • 2012-05-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-03-07
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多