问题描述
我有以下 C 库(特别是我现在正在调试的函数是 pass_by_reference
):
#include <stdlib.h>
double multiply_numbers(double a,double b);
double *get_array(double a);
void pass_by_reference(int *a);
double multiply_numbers(double a,double b) {
return a*b;
}
double *get_array(double a) {
double *retval;
int i;
retval = malloc(100*sizeof(a));
for(i=0; i<100; i++) {
retval[i] = i*a;
}
return retval;
}
void pass_by_reference(int *a) {
*a = 8;
}
我正试图用一个名为 pass_by_reference
的 Fortran 子程序来包装它(后者将在 python 中通过 f2py
调用):
module test_c_lib
use iso_c_binding
implicit none
contains
subroutine multiply(x,y,z)
use iso_c_binding
real(8),intent(in) :: x
real(8),intent(in) :: y
real(8),intent(out) :: z
! Interface to C function
interface
real(c_double) function c_multiply_numbers(a,b) bind(C,name="multiply_numbers")
import
real(c_double),value :: a,b
end function
end interface
! Call C function
z = c_multiply_numbers(x,y)
end subroutine
subroutine get_array(x,intent(out) :: z(100)
type(c_ptr) :: ret_c_ptr
real(8),pointer :: f_ptr(:)
! Interface to C function
interface
type(c_ptr) function c_get_array(a) bind(C,name="get_array")
import
real(c_double),value :: a
end function
end interface
! Call C function
ret_c_ptr = c_get_array(x)
call c_f_pointer(ret_c_ptr,f_ptr,[100])
z = f_ptr
end subroutine
subroutine pass_by_reference(z)
use iso_c_binding
integer,intent(out) :: z
! Interface to C function
interface
type(c_null_ptr) function c_pass_by_reference(a) bind(C,name="pass_by_reference")
import
type(c_int),value :: a
end function
end interface
! Call C function
c_pass_by_reference(z)
end subroutine
end module
以及对应的makefile:
$ cat makefile
f_mod.so: f_mod.f90 c_lib.o
f2py -c f_mod.f90 c_lib.o -m f_mod
c_lib.o: c_lib.c
gcc -c -fpic c_lib.c -o c_lib.o
尝试使用 f2py
编译时,我得到:
57 | use iso_c_binding
| 2
......
63 | type(c_null_ptr) function c_pass_by_reference(a) bind(C,name="pass_by_reference")
| 1
Error: Type name 'c_null_ptr' at (1) conflicts with prevIoUsly declared entity at (2),which has the same name
f_mod.f90:65:43:
57 | use iso_c_binding
| 2
......
65 | type(c_int),value :: a
| 1
Error: Type name 'c_int' at (1) conflicts with prevIoUsly declared entity at (2),which has the same name
f_mod.f90:63:24:
63 | type(c_null_ptr) function c_pass_by_reference(a) bind(C,name="pass_by_reference")
| 1
Error: The type for function 'c_pass_by_reference' at (1) is not accessible
f_mod.f90:63:24: Warning: Implicitly declared BIND(C) variable 'c_pass_by_reference' at (1) may not be C interoperable [-Wc-binding-type]
f_mod.f90:70:35:
70 | c_pass_by_reference(z)
| 1
Error: 'c_pass_by_reference' at (1) is not a variable
f_mod.f90:63:24-71:
63 | type(c_null_ptr) function c_pass_by_reference(a) bind(C,name="pass_by_reference")
| 2 1
Warning: Implicitly declared variable 'a' at (1) may not be C interoperable but it is a dummy argument to the BIND(C) procedure 'c_pass_by_reference' at (2) [-Wc-binding-type]
f_mod.f90:63:24:
63 | type(c_null_ptr) function c_pass_by_reference(a) bind(C,name="pass_by_reference")
| 1
Warning: Implicitly declared BIND(C) function 'c_pass_by_reference' at (1) may not be C interoperable [-Wc-binding-type]
error: Command "/usr/local/bin/gfortran9 -Wall -g -fno-second-underscore -fPIC -O3 -funroll-loops -I/tmp/tmpk7tn1bgi/src.freebsd-12.2-RC1-amd64-3.7 -I/usr/local/lib/python3.7/site-packages/numpy/core/include -I/usr/local/include/python3.7m -c -fPIC f_mod.f90 -o /tmp/tmpk7tn1bgi/f_mod.o -J/tmp/tmpk7tn1bgi/ -I/tmp/tmpk7tn1bgi/" Failed with exit status 1
*** Error code 1
我有两个问题:
- 当使用
iso_c_binding
时,在此特定示例中,传递给a
函数的变量pass_by_reference
是实际通过引用传递还是我必须在界面中指定不同的内容? - 为什么
f2py
报告Type name 'c_int' at (1) conflicts with prevIoUsly declared entity at (2),which has the same name
? - 如何指定 C 函数不返回任何内容 (
void
)?我曾尝试使用type(c_null_ptr)
解决方法
在执行评论中指出的所有更正后,这是有效的封装:
module test_c_lib
use iso_c_binding
implicit none
contains
subroutine multiply(x,y,z)
use iso_c_binding
real(8),intent(in) :: x
real(8),intent(in) :: y
real(8),intent(out) :: z
! Interface to C function
interface
real(c_double) function c_multiply_numbers(a,b) bind(C,name="multiply_numbers")
import
real(c_double),value :: a,b
end function
end interface
! Call C function
z = c_multiply_numbers(x,y)
end subroutine
subroutine get_array(x,intent(out) :: z(100)
type(c_ptr) :: ret_c_ptr
real(8),pointer :: f_ptr(:)
! Interface to C function
interface
type(c_ptr) function c_get_array(a) bind(C,name="get_array")
import
real(c_double),value :: a
end function
end interface
! Call C function
ret_c_ptr = c_get_array(x)
call c_f_pointer(ret_c_ptr,f_ptr,[100])
z = f_ptr
end subroutine
subroutine pass_by_reference(z)
use iso_c_binding
integer,intent(out) :: z
! Interface to C function
interface
subroutine c_pass_by_reference(a) bind(C,name="pass_by_reference")
import
integer(c_int) :: a
end subroutine
end interface
! Call C function
call c_pass_by_reference(z)
end subroutine
end module