2016-11-23 6 views
1

Я изучаю C совместимость FORtran в течение нескольких дней, чтобы вызвать Fortran функцию DLL из C. Здесь я нашел эту ссылку: Use Fortran-code in CОб использовании Fortran функции в C с iso_c_binding

Я пытаюсь создать Fortran DLL, как это и мой компилятор Intel Fortran компилятор:

module integration 
    implicit none 

contains 

    function Integrate(func, a,b, intsteps) result(integral) 
!DEC$ ATTRIBUTES DLLEXPORT :: Integrate 
    interface 
     real function func(x) 
     real, intent(in) :: x 
     end function func 
    end interface 

    real :: integral, a, b 
    integer :: intsteps 
    intent(in) :: a, b, intsteps 
    optional :: intsteps 

    real :: x, dx 
    integer :: i,n 
    integer, parameter :: rk = kind(x) 

    n = 1000 
    if (present(intsteps)) n = intsteps 

    dx = (b-a)/n 

    integral = 0.0_rk 
    do i = 1,n 
     x = a + (1.0_rk * i - 0.5_rk) * dx 
     integral = integral + func(x) 
    end do 

    integral = integral * dx 
    end function 

end module integration 


    real(c_float) function wrapper_integrate(func, a, b, intsteps) result(integral) bind(C, name='integrate') 
    use iso_c_binding 
    use integration 

interface 
    function iFunc(x) bind(C) 
     use, intrinsic :: iso_c_binding 
     real(c_float) :: iFunc 
     real(c_float), intent(in) :: x 
    end function iFunc 
    end interface 

    type(C_FUNPTR), INTENT(IN), VALUE :: func 
    real(c_float) :: a,b 
    integer(c_int),intent(in) :: intsteps 
    optional :: intsteps 

    procedure(iFunc),pointer :: myfunc 
    call c_f_procpointer(func, myfunc) 

    if (present(intsteps)) then 
    integral = Integrate(myfunc,a,b,intsteps) <==error #8128 
    else 
    integral = Integrate(myfunc,a,b)   <==error #8128 
    endif 

end function wrapper_integrate 

Когда я построил DLL, ошибка показывает ниже

error #8128: The BIND attribute of the associated actual procedure differs from the BIND attribute of the dummy procedure. [MYFUNC] 

Строка ошибки, обозначенная в коде, выглядит как myfunc не равна func, определенной в интеграции модулей. Возможно, я могу использовать iso_c_binding для модификации модуля integration.

Иногда некоторые функции Fortrans имеют множество аргументов, которые должны быть назначены и использованы в функции, это не простой способ использовать iso_c_binding в Fortran. Итак, как решить ошибку в MYFUNC?

+0

Фиктивная процедура в 'Integrate' имеет атрибут' bind'; указатель функции 'myfunc', который является фактическим аргументом, имеет интерфейс, заданный' iFunc', который не имеет интерфейса 'bind'. – francescalus

+0

Да! Я забыл об этом! Теперь я могу экспортировать Fortran Dll. – radiosan

+0

И спасибо за редактирование моего вопроса, который делает его аккуратным! – radiosan

ответ

2

Если фиктивная процедура имеет явный интерфейс, то ее характеристики должны быть такими же, как и характеристики фактической процедуры, за исключением некоторых вещей, которые здесь не актуальны.

Характеристики процедуры включают в себя наличие атрибута BIND.

Чтобы согласовать характеристики, вы можете использовать небольшую промежуточную процедуру, которая не имеет BIND (C), для вызова вашей предоставленной процедуры BIND (C).

Например, с некоторыми другими изменениями, чтобы избежать предположений вокруг того, номинированный c_float и c_int по умолчанию действительных и целых виды:

function wrapper_integrate(func, a, b, intsteps) & 
    result(integral) bind(C, name='integrate') 
    use iso_c_binding 
    use integration 
    implicit none 

    interface 
    function func(x) bind(C) 
     use, intrinsic :: iso_c_binding 
     implicit none 
     real(c_float), intent(in) :: x 
     real(c_float) :: func 
    end function func 
    end interface 

    real(c_float), intent(in) :: a,b 
    integer(c_int), intent(in), optional :: intsteps 
    real(c_float) :: integral 

    real :: local_a, local_b 
    integer :: local_intsteps 

    local_a = a 
    local_b = b 
    if (present(intsteps)) then 
    local_intsteps = intsteps 
    integral = Integrate(local_func, a, b, local_intsteps) 
    else 
    integral = Integrate(local_func, a, b) 
    end if 
contains 
    function local_func(x) 
    real, intent(in) :: x 
    real :: local_func 

    real(c_float) :: local_x 

    local_x = x 
    local_func = func(local_x) 
    end function local_func 
end function wrapper_integrate 

Обратите внимание, что наличие дополнительных аргументов в интероперабельных процедурах является Fortran 2015 особенности.

+0

Спасибо! Мне нужно это изучить! – radiosan

+0

Кстати, Intel Fortran можно вызвать в .NET Framework? – radiosan

+0

bind (C, name = 'integrate') должен быть bind (C, name = 'wrapper_integrate'), и он работает! И этот метод очень полезен для меня. – radiosan