奇怪的VS名称破坏行为?

时间:2015-09-08 01:29:42

标签: c++ visual-studio-2012 name-mangling

考虑以下无操作代码,我在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[]来解决VS中的这个问题,但这不是必需的,因为char *argv[]char **argv完全意味着用于声明参数时也是如此。

我还没有尝试过,但它让我想知道VS是否也会考虑这两个版本因超载而不同。

2 个答案:

答案 0 :(得分:5)

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

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

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

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

int test(int argc, char **argv)
{
   return 0;
}

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

答案 1 :(得分:0)

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

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