【发布时间】:2019-03-03 01:29:48
【问题描述】:
我正在学习 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 *,但无论如何它都适用于现代架构。
我一直在尝试创建一个独特的 Fortran 类型,更接近不透明 C 指针的意图。唯一对我有用的是:
type, bind(c) :: foobar
private
type(c_ptr) :: ptr
end type
对应于:
typedef struct {
void * ptr;
} foobar;
在 C 端。现在,C 标准的 §6.7.2.1 保证 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
我已经验证,对于使用此类型定义从 Fortran 调用 C 函数 foo_create() 和 foo_destroy() 的程序,Valgrind 没有显示错误。不过,这不能作为一个确定的证据。
struct { void * ptr } 与struct foobar_s * 具有相同大小和位模式的假设会被打破吗?这是在 Fortran 2003 中包装不透明 C 指针(并创建不同类型)的最佳方式吗?
【问题讨论】:
-
对所有 Fortran 问题使用标签 fortran 以获得更多关注(与使用 c 而不是 c99 的方式相同)。
-
我不明白为什么您希望您的 Fortran 包装器
foobar具有互操作性 - 它使 Fortran 类型不那么明显。根据您的操作,大小和位模式相同是不够的 - 例如调用约定可能会有所不同,具体取决于您处理的是原始值还是聚合。或许可以举一个例子说明您的想法,以获得更相关的评论。 -
@IanH,我使用
bind(c)直接从 Fortran 调用库的 C API,以要求 Fortran 编译器遵循 C 调用约定。我想要一个 Fortran 类型,它 (1) 行为与指向结构的不透明指针完全一样,并且 (2) 与 Fortran 端的其他类型不同。我将在问题中添加一些示例。
标签: c fortran fortran2003 opaque-pointers