奇怪的VS名称破坏行为?

Ben*_*ity 4 c++ name-mangling visual-studio-2012

考虑以下无操作代码,我在Win10 64位上编译为C++:

int test(int argc, char *argv[]);
int main(int argc, char *argv[])
{
   return test(argc, argv);
}

int test(int argc, char **argv)
{
   return 0;
}
Run Code Online (Sandbox Code Playgroud)

如果所有这些代码都放在同一个.cpp文件中,它会在VS2012,VS2013,VS2015和mingw32-g ++ v4.7.1中正确编译和链接,正如我所期望的那样.

但是,如果我只是将测试函数的定义移动到一个单独的文件中,生成的两个文件仍然可以编译并与mingw编译器正确链接,但在VS的所有版本上我得到:

error LNK2019: unresolved external symbol "int __cdecl test(int,char * * const)" (?test@@YAHHQAPAD@Z) referenced in function _main"
Run Code Online (Sandbox Code Playgroud)

我可以通过简单地改变测试功能做argv参数的声明中VS解决此问题char *argv[],但不应该是必要的,因为char *argv[]char **argv用来声明参数时的意思完全一样的东西.

我没有尝试过,但它让我想知道VS是否也会考虑两个版本不同的重载目的.

Jam*_*lis 6

是的,这是Visual C++名称装饰方案中的错误.对于指针类型参数,顶级const和volatile限定符被编码到修饰名称中,即使它们与函数类型无关.因此,举例来说,char**char** const以不同的编码.(在您的示例中,char*[]相当于char** const.)

在确定如何修饰函数名时,编译器将使用函数的第一个声明,即使定义与第一个声明不完全匹配.这就是为什么您的示例链接在定义与main函数位于同一源文件中时:test函数使用第一个声明所需的名称进行修饰,该声明与main函数中引用的名称相同.

如果将声明和定义都移动到单独的源文件中,例如,

int test(int argc, char *argv[]);

int test(int argc, char **argv)
{
   return 0;
}
Run Code Online (Sandbox Code Playgroud)

那么你的程序也会成功链接,原因相同.这就是为什么这个"bug"通常不是问题的原因:通常在跨多个翻译单元使用函数时,它们在头文件中声明,并且在任何地方都有一个声明.