2017-01-03 3 views
0

Я пытаюсь скомпилировать с Visual Studio 2012 тестовую программу, которая должна ссылаться на файл test.lib, предоставленный мне коллегой.ошибка связи: символ функции __thiscall не найден, но символ функции __cdecl определен

Компиляция останавливается на этапе связывания с ошибкой LNK2019. Отсутствующий символ:

public: virtual __thiscall abc::Test::~Test(void) 

Использование утилиты dumpbin, я обнаружил, что внутри test.lib следующий символ определяется:

public: virtual __cdecl abc::Test::~Test(void) 

В чем разница между этими двумя функциями? Как я могу исправить эту проблему компиляции? Я не хватает некоторых флагов компиляции?

+0

Вы определили деструктор? – Raindrop7

+0

Скорее всего, вы компилируете свою тестовую программу с различными параметрами компилятора, чем то, с чем собрал ваш коллега. Разница в вызове конвенции заставляет меня поверить в это. – PaulMcKenzie

+0

@ Raindrop7: деструктор определен – carlo

ответ

1

Вам не нужны флаги.

Calling convention modifiers, такие как __thiscall и __cdecl, изменить имя функции внутри. Таким образом, __thiscall abc::Test::~Test(void) является не такая же функция, как __cdecl abc::Test::~Test(void). Чтобы исправить это, измените __thiscall на __cdecl.

IIRC, __cdecl - соглашение по умолчанию для MSVC (компилятор Visual Studio), поэтому, если ваш коллега не указал ничего особенного, dumpbin будет описывать функцию как имеющую соглашение о вызове __cdecl.

Объяснение:

В отличие от C, внутреннее имя C++ функции, методы и объекты не так же, как те, в ваших исходных файлов. Это называется name mangling (иногда называется название украшения). Имя коверкание позволяет функциям быть перегружен, то есть, есть несколько функций, которые отличаются только по типу аргумента, а также членство класса/пространства имен и т.д.

Предположим, у меня есть следующая программа C:

// Foo.c 
#include <stdio.h> 

void myPrint(void) { 
    printf("Hello, World!\n"); 
} 

void myPrint(const char* str) { 
    printf(str); 
} 

int main() { 
    myPrint(); 
    myPrint("Hello, World!\n"); 
} 

Если вы пытаетесь скомпилировать его как код C:

$ gcc -o Foo Foo.c 
Foo.c:7:6: error: redefinition of ‘myPrint’ 

Но если попытаться скомпилировать это как C++:

$ g++ -o Foo Foo.c 

Он компилируется.

Если вы пытаетесь просмотреть сборку с g++ -o Foo.s Foo.cpp -S -Os, вы увидите, что искаженное имя void myPrint(void); функции является _Z7myPrintv (конечными v стендов для void), в то время как искаженное имя void myPrint(const char*); функции является _Z7myPrintPKc (PKc: Указатель на Konstant Чар).

Кстати, искаженное имя функции зависит от используемого вами компилятора. С MSVC (компилятор Visual Studio) void myPrint(const char*); имеет следующее поврежденное имя: [email protected]@[email protected].

+0

Спасибо за объяснение. Проблема, которую я имею сейчас, заключается в том, что я не знаю, как изменить __thiscall на __cdecl. Я просмотрел код и не нашел ничего, что предполагает компиляцию с помощью __thiscall или __cdecl. – carlo

+0

Не смотрите на код. Посмотрите варианты генерации кода. Возможно, библиотека была скомпилирована с различными настройками оптимизации или другими настройками. Вам необходимо загрузить как проект, так и проект библиотеки в Visual Studio и обеспечить, чтобы все настройки, связанные с генерацией кода, были одинаковыми. – PaulMcKenzie

+0

@PaulMcKenzie - В оригинальном посте я не упоминал, что я использую CMake с генератором Visual Studio 11. Я только что провел эксперимент со Scons и скомпилировал его (я тщательно добавил все определения и флаги, добавленные автоматически CMake)! Но поскольку флаги и определения одинаковы, что еще может быть? Я запускаю оба компиляции из одного и того же стандартного запроса. – carlo