Я написал некоторый код для загрузки динамической библиотеки, которая была скомпилирована в Fortran. Среди экспортируемых функций в библиотеке Фортрана есть экспортируемые сеттеры и геттеры. Я пытаюсь загрузить эти установщики и получатели, используя Windows API. Хотя это работает для моего кода, встроенного в отладку. Он не работает с моим кодом, встроенным в релиз. В релизе, когда я пытаюсь пройти 1.0f
Через set()
я вижу 0.0f
в отладчике, когда я вхожу в код Fortran.
Изменить: еще одно наблюдение, которое я забыл упомянуть. Если бы я только загрузить setValue()
функция. Моя проблема полностью уходит. Только когда я загружаю дополнительные функции из библиотеки, у меня появляются проблемы, которые я вижу.
Составители
отладка
Я определил, что когда мой код C ++ скомпилирован в выпуске, мой загруженный set()
функция пройдет 0.0f
в Фортран функции. Это было обнаружено путем загрузки отладочной версии библиотеки fortran и запуска ее через отладчик Visual Studio. Выполнение того же самого с отладочной сборкой моего кода дает правильное значение, передаваемое функции fortran.
Я попробовал следующее в попытке выяснить, что происходит:
FORTRAN
REAL FUNCTION getValue()
!DEC$ ATTRIBUTES DLLEXPORT, c:: getValue
IMPLICIT NONE
INCLUDE 'VALUE.CMN'
getValue = VAL
RETURN
END FUNCTION getValue
SUBROUTINE setValue(x)
!DEC$ ATTRIBUTES DLLEXPORT, c:: setValue
IMPLICIT NONE
INCLUDE 'VALUE.CMN'
REAL, INTENT(IN) :: x
VAL = x
END SUBROUTINE setValue
C ++
const auto handle = reinterpret_cast<HMODULE>(LoadLibrary("fortran_value.dll"));
typedef void(*Set)(float&);
typedef float(*Get)(void);
const auto set = reinterpret_cast<Set>(GetProcAddress(handle, "setvalue"));
const auto get = reinterpret_cast<Get>(GetProcAddress(handle, "getvalue"));
auto value = 1.0f;
// 0.0f gets set to the internal fotran variable when this code is compile in release.
set(value);
// Only succeeds when this code is compiled in Debug.
// get() returns 0.0f when this code is compiled in Release.
if(value == get())
{
std::cout << "Success!\n";
}
else
{
std::cout << "Fail!\n";
}
FreeLibrary(handle);
Я в недоумении. Любые мысли или предложения о том, что здесь может происходить?
ПОЛНЫЙ СОВМЕСТНЫЙ ПРИМЕР
Ниже приведены ссылки на полный скомпилированный пример проблемы, с которой я столкнулся. После того, как у вас будет больше времени, чтобы провести с ним. Похоже, мои проблемы связаны с моими попытками создать оболочку с приведенным выше кодом.
Прочитав ответы на мой вопрос, я потратил больше времени на отладку кода на фортране и на дальнейшие исследования. Как обсуждалось в ответах на мой вопрос, было несоответствие в соглашениях о вызовах. Используя bind (c) в моем коде на фортране, моя проблема была решена.
Начиная с Fortran 2003 (ISO / IEC 1539-1: 2004 (E)) существует стандартизированный способ генерации объявлений процедур и производных типов и глобальных переменных, которые совместимы с C (ISO / IEC 9899: 1999). связывания (С) атрибут был добавлен для информирования компилятора о том, что символ должен взаимодействовать с C; также добавлены некоторые ограничения. Обратите внимание, однако, что не все функции C имеют эквивалент Fortran или наоборот. Например, ни целые числа без знака C, ни функции C с переменным числом аргументов не имеют эквивалента в Fortran
REAL FUNCTION getValue() bind(c)
!DEC$ ATTRIBUTES DLLEXPORT :: getValue
IMPLICIT NONE
INCLUDE 'VALUE.CMN'
getValue = VAL
RETURN
END FUNCTION getValue
SUBROUTINE setValue(x) bind(c)
!DEC$ ATTRIBUTES DLLEXPORT :: setValue
IMPLICIT NONE
INCLUDE 'VALUE.CMN'
REAL, INTENT(IN) :: x
VAL = x
END SUBROUTINE setValue
Других решений пока нет …