Я изучаю Fortran 2003. В качестве учебного задания я пытаюсь звонить из Fortran 2003 в библиотеку C, в которой используются непрозрачные указатели:
struct foobar_s;
typedef struct foobar_s *foobar;
foobar foo_create(enum foo, unsigned int);
void foo_destroy(foobar);
Большинство советов, которые я нашел в Интернетеговорит мне описать тип foobar
как type(c_ptr)
, поэтому должно работать следующее:
!foobar foo_create(enum foo, unsigned int);
function foo_create(mode,n) bind(c) ret(foo)
type(c_ptr) :: foo
integer(kind(ENUM_FOO_CONSTANT)), value :: mode
integer(kind=c_int), value :: n
end function
Это объявляет foo_create
как возвращающее void*
вместо foobar
= struct foobar_s *
, но все равно работает на современных архитектурах.
Я пытался создать отдельный тип Фортрана, ближе к цели непрозрачного указателя Си.Единственное, что сработало для меня, это:
type, bind(c) :: foobar
private
type(c_ptr) :: ptr
end type
, что соответствует:
typedef struct {
void * ptr;
} foobar;
на стороне C.Теперь §6.7.2.1 стандарта C гарантирует, что адрес начала struct
является адресом первого элемента (верно?), Но в его конце может быть некоторое заполнение (но на архитектурах, которые я там использую)это не так, потому что указатели выровнены), поэтому вся эта штуковина работает на моих машинах:
!foobar foo_create(enum foo, unsigned int);
function foo_create(mode,n) bind(c) ret(foo)
type(foobar) :: foo
integer(kind(ENUM_FOO_CONSTANT)), value :: mode
integer(kind=c_int), value :: n
end function
!void foo_destroy(foobar);
sobroutine foo_destroy(foo) bind(c)
type(foobar), value :: foo
end subroutine
Я убедился, что Valgrind не показывает ошибок для программы, которая вызывает функции C foo_create()
и foo_destroy()
из Фортрана, использующего это определение типа.Тем не менее, это не может быть определенным доказательством.
Предполагается ли, что struct { void * ptr }
имеет тот же размер и битовый шаблон, что и struct foobar_s *
, сломается?Это лучший способ обернуть непрозрачный указатель C (и создать отдельный тип) в Fortran 2003?