奇怪的VS名称混淆行为

Odd VS name mangling behavior?

本文关键字:VS      更新时间:2023-10-16

考虑以下不做任何事情的代码,我将其编译为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;
}

如果所有这些代码都放在同一个。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"

我可以通过简单地将测试函数中的参数argv的声明更改为char *argv[]来解决这个问题,但这应该是不必要的,因为char *argv[]char **argv在用于声明参数时意味着完全相同的事情。

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

是的,这是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;
}

,那么您的程序也将成功链接,出于同样的原因。这就是为什么这个"bug"通常不是一个问题:通常当函数在多个翻译单元中使用时,它们是在头文件中声明的,并且到处都包含一个声明。

对于单独的文件,根据错误消息使用test(int argc, char ** const argv)。请注意,数组(char *argv[])的地址将是常数(因此argv将是常数),而不是指针指向指针(char **argv)。虽然因为argv是按值传递的,它不能被修改,所以我不确定为什么VS对这个很挑剔。

当两个函数都在同一个文件中时,显然VS可以检测到test()没有修改argv,所以它不会报错。

相关文章:
  • 没有找到相关文章