C 프로그램에서 호출되는 Fortran DLL이 있으며 내 프로 시저 중 하나는 C 프로그램에서 제공하는 콜백 함수를 주기적으로 호출해야합니다. 현재 '간단한'형태로 잘 작동하지만 파생 된 형식 내에 콜백 포인터를 저장하여 Fortran 코드 내에서 더 쉽게 전달할 수 있기를 원합니다. 지금까지 내가 시도한 것은 작동하지 않는 것 같습니다.
여기로 시작하는 것은 내가 지금 가지고 있고, 이것이 무엇을 수행 작업 :
C (OK, 실제로는 C ++) 프로그램에서 시작하여 콜백의 헤더 프로토 타입은 다음과 같습니다.
typedef void (*fcb)(void *)
Fortran 호출의 프로토 타입은 다음과 같습니다.
extern "C" __declspec(dllexport) int fortran_function(int n,
uchar *image_buffer,
fcb callback,
void *object);
실제 콜백 함수는 다음과 같습니다.
void callback(void* pObject)
{
// Cast the void pointer back to the appropriate class type:
MyClass *pMyObject = static_cast<MyClass *>(pObject);
pMyObject -> updateImageInGUI();
}
C ++에서 Fortran 코드에 대한 호출은 다음과 같습니다.
int error = fortran_function(m_image.size(), m_image.data, callback, this);
여기서는 m_image
현재 객체의 멤버 속성 인 이미지 데이터의 배열입니다. C ++는 원시 이미지 데이터를 Fortran DLL에 전달하고 Fortran에 처리하도록 요청합니다. 이렇게하면 시간이 오래 걸리기 때문에 Fortran은 주기적으로 이미지 버퍼를 업데이트하고 콜백을 호출하여 GUI를 새로 고칩니다. 어쨌든 Fortran 측으로 이동하여 C 콜백에 대한 인터페이스를 정의합니다.
abstract interface
subroutine c_callback(c_object) bind(c)
use, intrinsic :: iso_c_binding
type(c_ptr), intent(in) :: c_object
end subroutine c_callback
end interface
다음과 같이 주요 Fortran 루틴을 정의합니다.
integer(c_int) fortran_function(n, image, callback, c_object) &
bind(c, name='fortran_function')
integer(c_int), value :: n
integer(4), intent(inout), dimension(n) :: image
procedure(c_callback) :: callback
type(c_ptr), intent(in) :: c_object
메인 루틴 어딘가에서 우리는 서브 루틴이라고 부릅니다 foo
.
call foo(data, callback, c_object)
... 여기서는 foo
다음과 같이 정의됩니다.
subroutine foo(data, callback, c_object)
type(my_type), intent(inout) :: data
procedure(c_callback) :: callback
type(c_ptr), intent(in) :: c_object
...
call callback(c_object)
...
end function foo
내가 말했듯이,이 모든 것이 잘 작동하며 오랫동안 그렇게 해왔습니다.
이제 내가 시도했지만 작동하지 않는 것들에 대해 :
구조의 필드에 인수를 복사하는 순진한 접근 방식
내가하는 일은 수정없이 원래 요소를 구조에 복사하는 것뿐이므로 이것이 작동 할 것으로 기대합니다. C 측에서는 아무것도 변경되지 않으며, 주요 Fortran 기능의 정의 나 c_callback
. 내가 할 일은 새로운 Fortran 파생 유형을 만드는 것입니다.
type :: callback_data
procedure(c_callback), pointer, nopass :: callback => null()
type(c_ptr) :: c_object
end type callback_data
그런 다음 내 주요 기능에서 C 응용 프로그램에서받은 값으로 이것을 채 웁니다.
data%callback_data%callback => callback
data%callback_data%c_object = c_object
call foo(data)
서브 루틴 foo가 약간 수정되어 이제 구조 내에서 콜백 및 C 객체를 찾습니다.
subroutine foo(data)
type(my_augmented_type), intent(inout) :: data
...
call data%callback_data%callback(data%callback_data%c_object)
...
end function foo
이것은 "0xffffffffffffffff 위치를 읽는 액세스 위반"으로 호출에서 실패합니다.
더 많은 iso_c_binding 기능을 사용하는 정교한 접근 방식
다시 C 측에서는 아무것도 변경되지 않지만 주 함수의 Fortran 측을 수정하여 콜백을 다음과 같이 수신합니다 c_funptr
.
integer(c_int) fortran_function(n, image, callback, c_object) &
bind(c, name='fortran_function')
integer(c_int), value :: n
integer(4), intent(inout), dimension(n) :: image
type(c_funptr), intent(in) :: callback
type(c_ptr), intent(in) :: c_object
추상 인터페이스를 subroutine c_callback
이전과 똑같이 정의 했지만, bind(c)
일부 를 그대로두고 생략하는 두 가지를 모두 실험 했습니다. 서브 루틴을 호출하는 주 함수 내의 코드 foo
는 다음과 같습니다.
call c_f_procpointer(callback, data%callback_data%callback)
data%callback_data%c_object = c_object
call foo(data)
... 서브 루틴 foo 자체가 이전 예제에서와 같이 여전히 정의되어 있습니다.
불행히도 이것은 이전 예제와 똑같은 방식으로 실패합니다.
여기서 달성하고자하는 것을 달성하기위한 올바른 구문이 있다고 가정하고 조언에 대해 매우 감사하겠습니다.
BIND(C)
VALUE 인수가없는 속성을 가진 Fortran 프로 시저의 더미 인수 는 C 측에서 포인터 매개 변수와 동일합니다 (이것은 참조로 전달되는 일반적인 Fortran 규칙과 대체로 일치합니다). 따라서 Fortran 측에 INTEGER(C_INT) :: a
(값 속성 없음)이 있으면 C 측에서 int *a
.
아마도 분명하지만 놀라운 결과를 가지 - 당신이있는 경우에 TYPE(C_PTR) :: p
, 그와 동등의 void **p
- C_PTR가 포인터하는 C_PTR이 값이 포인터에 대한 포인터없이 통과되도록. 이것이 주어지면 콜백에 대한 인터페이스가 나옵니다 (를 추가해야 함 VALUE
).
Fortran에서 함수에 대한 C 포인터에 대한 유형 의미에서 상호 운용 가능한 아날로그는 TYPE(C_FUNPTR)
. VALUE 속성 및 C_PTR
적용 의 부재와 관련하여 동일한 고려 사항이 있습니다. 선언 된 인수는 TYPE(C_FUNPTR) :: f
함수에 대한 포인터에 대한 포인터입니다. 이것과 Fortran의 C 측 호출이 주어지면 함수 포인터에 해당하는 인수에는 VALUE
속성 이 있어야 합니다.
Fortran 프로 시저 포인터가 작동한다는 사실은 C 함수 포인터 및 Fortran 프로 시저 포인터의 기본 구현과 Fortran 프로 시저 포인터가 전달되는 방식의 우연한 일치 일뿐입니다.
전체적으로 Fortran 절차에는 다음과 같은 인터페이스가 있어야합니다.
integer(c_int) fortran_function(n, image, callback, c_object) &
bind(c, name='fortran_function')
integer(c_int), value :: n
integer(c_signed_char), intent(inout), dimension(n) :: image
type(c_funptr), intent(in), value :: callback
type(c_ptr), intent(in), value :: c_object
(원래 코드에서 이미지 배열에 대한 선언이 잘못된 것 같습니다. 아마도 위의 내용은 적절하지 않을 수도 있습니다)
C 콜백의 인터페이스 선언에는 다음과 같은 인터페이스가 있어야합니다.
abstract interface
subroutine c_callback(c_object) bind(c)
use, intrinsic :: iso_c_binding
implicit none
type(c_ptr), intent(in), value :: c_object
end subroutine c_callback
end interface
(마찬가지로 당신이되었습니다 지난 몇 개월 동안 인텔 포럼 (논의?), 현재 ifort 그것의 취급있어에 문제가있을 수 있습니다 C_PTR
와 VALUE
.)
이 기사는 인터넷에서 수집됩니다. 재 인쇄 할 때 출처를 알려주십시오.
침해가 발생한 경우 연락 주시기 바랍니다[email protected] 삭제
몇 마디 만하겠습니다