2015-09-08 5 views
1

Рассмотрим следующий ничегонеделания код, который я компиляции в C++ на Win10 64-битном:Нечетное поведение имени пользователя?

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)" ([email protected]@[email protected]) referenced in function _main" 

I может решить эту проблему в VS, просто изменив объявление параметра argv в тестовой функции на char *argv[], но это не обязательно, поскольку char *argv[] и char **argv означают то же самое, что и при объявлении параметра.

Я не пробовал, но меня заставляет задуматься, будет ли VS рассматривать две версии, отличающиеся друг от друга для перегрузки.

ответ

3

Да, это ошибка в схеме оформления имен Visual C++. Для параметров типа указателя верхние константы и изменчивые квалификаторы кодируются в декорированное имя, хотя они не имеют отношения к типу функции. Так, например, char** и char** const кодируются по-разному. (В вашем примере char*[] эквивалентен char** const.)

При определении того, как украсить имя функции, компилятор будет использовать первое объявление функции, даже если определение не соответствует первому объявлению. Вот почему ваш пример связывается, когда определение находится в том же исходном файле, что и основная функция: тестовая функция украшена именем, требуемым первым объявлением, которое является тем же именем, на которое ссылается основная функция.

Если вы двигаетесь как декларацию и определение в отдельный исходный файл, например,

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

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

тогда ваша программа будет ссылка успешно, по той же причине. Вот почему эта «ошибка» обычно не является проблемой: обычно, когда функции используются в нескольких единицах перевода, они объявляются в файле заголовка, и есть одно объявление, которое включено повсюду.

+0

Неужели кто-нибудь зарегистрировал ошибку? – MikeMB

+0

@MikeMB Я уверен, что за последние годы об этом сообщается множество ошибок. Если вы хотите, вы можете открыть еще один файл https://connect.microsoft.com/VisualStudio. Обратите внимание, что это ошибка, при которой затраты на ее фиксацию очень высоки, но преимущество исправления очень низкое. Вряд ли это будет исправлено в ближайшее время (если вообще). –

+0

@James McNellis У меня есть дополнительный вопрос о вашем утверждении, что 'char * []' эквивалентно 'char ** const' в моем примере. Почему 'const'? Я всегда думал, что только для параметров, '* []' эквивалентен '**', но, похоже, я ошибаюсь. Является ли const каким-то образом подразумевается '[]'?Язык C99 говорит, что и «argv», и строки, которые он представляет, могут быть модифицируемыми (хотя в нем ничего не говорится о фактических элементах «argv»). Однако я не мог найти это утверждение на C++ 11. – BenevolentDeity

0

Для отдельного файла используйте тест (int argc, char ** const argv) на основе сообщения об ошибке. Обратите внимание, что адрес массива (char * argv []) будет постоянным (поэтому argv будет постоянным), в отличие от указателя на указатель (char ** argv). Хотя, поскольку argv передается по значению, его нельзя изменить, поэтому я не уверен, почему VS обманывает об этом.

Если обе функции находятся в одном файле, очевидно, VS может обнаружить, что test() не изменяет argv, поэтому он не жалуется.

 Смежные вопросы

  • Нет связанных вопросов^_^