gfortran:将逻辑参数从 C 传递给 Fortran 函数
gfortran: pass logical argument to Fortran function from C
调用带有 logical
个参数的 Fortran 函数时,我应该在 C 中使用什么参数类型,特别是 gfortran? gfortran 的文档在哪里?
这是一个没有警告就无法编译的示例程序:
one.f
的内容:
subroutine proc1(x)
logical x
end
main.c
的内容:
void proc1_(_Bool *x);
int main() {
_Bool x;
proc1_(&x);
return 0;
}
如果我按如下方式使用 GCC 进行编译,并启用 LTO,我会收到有关函数原型不匹配的警告:
gfortran -flto -c one.f
gcc -flto -c main.c
gcc -flto main.o one.o
我收到的警告:
main.c:2:6: warning: type of 'proc1_' does not match original declaration [-Wlto-type-mismatch]
2 | void proc1_(_Bool *x);
| ^
one.f:2:22: note: 'proc1' was previously declared here
2 | subroutine proc1(x)
| ^
one.f:2:22: note: code may be misoptimized unless '-fno-strict-aliasing' is used
请注意,启用 LTO 允许链接器验证原型之间的参数类型是否匹配。不幸的是,使用 LTO 不是我们的选择。 CRAN 要求提交的代码在启用 LTO 的情况下编译时不会出现这些警告。
我只在尝试使用 logical
参数时才发现问题。 real
、integer
和 character
都可以。
可以要求 gfortran 生成 C 原型,这是它给我的输出:
gfortran -flto -fc-prototypes-external -c one.f
void proc1_ (int_fast32_t *x);
在 C 原型中使用 int_fast32_t
也不起作用。我试过的类型都没有,int
和 _Bool
都没有。通常,当原型之间存在类型不匹配时,错误消息会提到类型应该是什么——但在这种情况下不会。
如何找到要使用的正确类型?
对于真正的现代 C-Fortran 互操作性,您应该使用 iso_c_binding
模块提供的类型(种类)并制作您的 Fortran 过程 bind(c)
。这样你就可以使用 logical(c_bool)
.
在旧式中,最好的办法是使用整数并传递一个 int
,并且只在 Fortran 中更正从 integer
到 logical
。老C没有bool
,是后来加的
变化最小:
subroutine proc1(x)
use iso_c_binding
logical(c_bool) x
end
#include <stdbool.h>
void proc1_(bool *x);
int main() {
bool x;
proc1_(&x);
return 0;
}
> gfortran -flto -c one.f
> gcc -flto -c main.c
> gcc -flto main.o one.o
在我的 Linux 和 GCC 7 和 10 上没有发出警告。
或进一步修改后:
subroutine proc1(x) bind(C, name="proc1")
use iso_c_binding
logical(c_bool), value :: x
end
#include <stdbool.h>
void proc1(bool x);
int main() {
bool x;
proc1(x);
return 0;
}
当然只有当它确实只是一个输入参数时才改变为按值传递。
正如 Vladimir F 在回答中所解释的那样,正确且保证可移植的解决方案是创建一个使用 ISO_C_BINDING 的 Fortran 包装器例程。这个包装器也可以借此机会制作一个更惯用的 C 接口,例如使用 value
说明符按值传递标量。
但是,对于在没有 LTO 的情况下适用于 GFortran 的快速而肮脏的解决方案(并且在某种程度上可能适用于其他编译器,但不能保证),请参阅 https://gcc.gnu.org/onlinedocs/gfortran/Internal-representation-of-LOGICAL-variables.html#Internal-representation-of-LOGICAL-variables 。也就是说,您可以传递一个适当大小的 C 整数变量,其中包含 1
表示真,0
表示假。这里适当的大小意味着除非你用 -fdefault-integer-8
或这样的编译选项编译你的 Fortran 代码,否则 GFortran 默认类型逻辑将是 4 个字节,所以一个普通的 C int
应该是好的(或 int32_t
如果你真的想确定的话,尽管我认为 GFortran 不支持任何 C int
不是 32 位的目标。
这不适用于 LTO 的原因是,虽然上述方法有效,但在 GCC 的内部,Fortran LOGICAL 变量几乎与整数相同,但不完全相同。所以在实践中,它们是具有最大值 1 和最小值 0 的特殊整数变量,即使它们占用更多 space(由它们的 kind 参数指定)。所以这种类型不匹配很可能就是它所抱怨的。不幸的是,除了上述通过 ISO_C_BINDING.
的正确解决方案外,没有解决方案
调用带有 logical
个参数的 Fortran 函数时,我应该在 C 中使用什么参数类型,特别是 gfortran? gfortran 的文档在哪里?
这是一个没有警告就无法编译的示例程序:
one.f
的内容:
subroutine proc1(x)
logical x
end
main.c
的内容:
void proc1_(_Bool *x);
int main() {
_Bool x;
proc1_(&x);
return 0;
}
如果我按如下方式使用 GCC 进行编译,并启用 LTO,我会收到有关函数原型不匹配的警告:
gfortran -flto -c one.f
gcc -flto -c main.c
gcc -flto main.o one.o
我收到的警告:
main.c:2:6: warning: type of 'proc1_' does not match original declaration [-Wlto-type-mismatch]
2 | void proc1_(_Bool *x);
| ^
one.f:2:22: note: 'proc1' was previously declared here
2 | subroutine proc1(x)
| ^
one.f:2:22: note: code may be misoptimized unless '-fno-strict-aliasing' is used
请注意,启用 LTO 允许链接器验证原型之间的参数类型是否匹配。不幸的是,使用 LTO 不是我们的选择。 CRAN 要求提交的代码在启用 LTO 的情况下编译时不会出现这些警告。
我只在尝试使用 logical
参数时才发现问题。 real
、integer
和 character
都可以。
可以要求 gfortran 生成 C 原型,这是它给我的输出:
gfortran -flto -fc-prototypes-external -c one.f
void proc1_ (int_fast32_t *x);
在 C 原型中使用 int_fast32_t
也不起作用。我试过的类型都没有,int
和 _Bool
都没有。通常,当原型之间存在类型不匹配时,错误消息会提到类型应该是什么——但在这种情况下不会。
如何找到要使用的正确类型?
对于真正的现代 C-Fortran 互操作性,您应该使用 iso_c_binding
模块提供的类型(种类)并制作您的 Fortran 过程 bind(c)
。这样你就可以使用 logical(c_bool)
.
在旧式中,最好的办法是使用整数并传递一个 int
,并且只在 Fortran 中更正从 integer
到 logical
。老C没有bool
,是后来加的
变化最小:
subroutine proc1(x)
use iso_c_binding
logical(c_bool) x
end
#include <stdbool.h>
void proc1_(bool *x);
int main() {
bool x;
proc1_(&x);
return 0;
}
> gfortran -flto -c one.f
> gcc -flto -c main.c
> gcc -flto main.o one.o
在我的 Linux 和 GCC 7 和 10 上没有发出警告。
或进一步修改后:
subroutine proc1(x) bind(C, name="proc1")
use iso_c_binding
logical(c_bool), value :: x
end
#include <stdbool.h>
void proc1(bool x);
int main() {
bool x;
proc1(x);
return 0;
}
当然只有当它确实只是一个输入参数时才改变为按值传递。
正如 Vladimir F 在回答中所解释的那样,正确且保证可移植的解决方案是创建一个使用 ISO_C_BINDING 的 Fortran 包装器例程。这个包装器也可以借此机会制作一个更惯用的 C 接口,例如使用 value
说明符按值传递标量。
但是,对于在没有 LTO 的情况下适用于 GFortran 的快速而肮脏的解决方案(并且在某种程度上可能适用于其他编译器,但不能保证),请参阅 https://gcc.gnu.org/onlinedocs/gfortran/Internal-representation-of-LOGICAL-variables.html#Internal-representation-of-LOGICAL-variables 。也就是说,您可以传递一个适当大小的 C 整数变量,其中包含 1
表示真,0
表示假。这里适当的大小意味着除非你用 -fdefault-integer-8
或这样的编译选项编译你的 Fortran 代码,否则 GFortran 默认类型逻辑将是 4 个字节,所以一个普通的 C int
应该是好的(或 int32_t
如果你真的想确定的话,尽管我认为 GFortran 不支持任何 C int
不是 32 位的目标。
这不适用于 LTO 的原因是,虽然上述方法有效,但在 GCC 的内部,Fortran LOGICAL 变量几乎与整数相同,但不完全相同。所以在实践中,它们是具有最大值 1 和最小值 0 的特殊整数变量,即使它们占用更多 space(由它们的 kind 参数指定)。所以这种类型不匹配很可能就是它所抱怨的。不幸的是,除了上述通过 ISO_C_BINDING.
的正确解决方案外,没有解决方案