Это происходит из-за искажения имени, выполненного C ++.
extern "C" vs no extern "C"
В качестве примера приведу то, что CFF Explorer показывает для таблицы экспорта библиотеки DLL.Первый был построен с помощью компилятора Borland c ++.Вторая была построена с использованием msvc.
Ordinal FunctionRVA Name RVA Name
00000001 0020E140 0032C2B6 createDevice
00000002 0020E244 0032C2C3 createDeviceEx
0000000D 00328DA4 0032C0C1 @irr@core@IdentityMatrix
0000000E 00328DE4 0032C28A @irr@video@IdentityMaterial
0000000C 000F9C80 001EE1B6 createDevice
0000000D 000F9CE0 001EE1C3 createDeviceEx
00000001 00207458 001EDDC7 ?IdentityMaterial@video@irr@@3VSMaterial@12@A
00000002 001F55A0 001EDDF5 ?IdentityMatrix@core@irr@@3V?$CMatrix4@M@12@B
Первые 2 функции createDevice
и createDeviceEx
содержат сигнатуру extern "C"
в своем прототипе, а другие нет.Обратите внимание на разницу в кодировании, когда используется искажение C ++.На самом деле разница на глубже .
ABI и стандартизация
Как объясняется в других ответах, стандарт C ++ не определяет A bstract B inary I nterface .Это означает, что поставщики, разрабатывающие свои инструменты, могут делать все, что им захочется, когда дело доходит до того, как обрабатываются вызовы функций и как перегрузка работает под капотом - при условии, что она демонстрирует ожидаемое поведение, как предписано стандартом.
При всех этих различных схемах кодирования у другого языка нет никакой надежды на работу с модулями, скомпилированными с C ++.Модули Heck, скомпилированные одним компилятором C ++, вряд ли будут работать с другим!Поставщики компиляторов могут по своему усмотрению менять кодировку между версиями.
Кроме того, отсутствие общего ABI означает, что не существует единого ожидаемого способа вызова этих функций / методов.Например, один компилятор может передавать свои аргументы в стеке, в то время как другой компилятор может передавать его в регистр.Один может передавать аргументы слева направо, а другой - наоборот.Если только один из этих аспектов не совпадает точно между вызывающим и вызываемым, то ваше приложение будет зависать ... то есть, если вам повезет.Вместо того, чтобы иметь дело с этим, поставщики просто говорят «нет», вызывая ошибку компоновки с различными кодировками.
OTOH, в то время как C также не имеет стандартизированного ABI, C является гораздо более простым языком для сравнения.,Большинство поставщиков компиляторов Си обрабатывают оформление функций и механизм вызова аналогичным образом.В результате существует своего рода «де-факто» стандарт, даже если ABI явно не указан в стандарте.Благодаря этой общности намного проще для других языков взаимодействовать с модулями, скомпилированными с C.
Например, украшение __stdcall
в сигнатуре функции понимается в соответствии с определенным соглашением о вызовах.Аргументы передаются справа налево, и вызываемый абонент отвечает за очистку стека после этого.__cdecl
похож, но понятно, что вызывающий отвечает за очистку стека.
Итог
Если данный модуль должен быть совместим с языками за пределамиC ++, правильно его декорировать и выставить как API C - ваш лучший выбор.Обратите внимание, что вы отказываетесь от некоторой гибкости, делая это.В частности, вы не сможете перегрузить эти функции, так как компилятор больше не может генерировать уникальные символы для каждой перегрузки с искажением имени.
Если совместимость не важна для рассматриваемого модуля - он только собираетсядля использования с тем же инструментом, с помощью которого он был построен, затем опустите украшение extern "C"
в своих прототипах.