考虑以下无操作代码,我在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是否也会考虑这两个版本因超载而不同。
答案 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,所以它不会抱怨。