奇怪的 VS 名称修改行为?

Odd VS name mangling behavior?

考虑以下不执行任何操作的代码,我在 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 中正确编译和 links,正如我所期望的那样。

但是,如果我只是将测试函数的定义移动到一个单独的文件中,生成的两个文件仍然可以编译并且 link 可以使用 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 是否也会出于重载目的考​​虑这两个不同的版本。

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

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

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

在确定如何修饰函数名时,编译器将使用函数的第一个声明,即使定义与第一个声明不完全匹配。这就是为什么你的例子 links 当定义与 main 函数在同一个源文件中时:测试函数用第一个声明所需的名称装饰,该名称与从内部引用的名称相同主要功能。

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

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

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

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