[英]Fortran iso_c_binding standard: Error: Type mismatch in argument 'test_variable' at (1); passed INTEGER(8) to TYPE(c_ptr)
我的現實生活中的程序使用整數 * 8 變量並且不使用這個特定的 iso_c_binding 補丁編譯,見下文。 當不使用 iso_c_binding package 時,我的程序運行良好。
在我的程序中使用 iso_c_binding package 時,我收到以下錯誤消息:
錯誤:(1) 處的參數“test_variable”中的類型不匹配; 將 INTEGER(8) 傳遞給 TYPE(c_ptr)
我從我的程序中創建了以下測試用例。 我的程序無法發布。 測試用例演示了我遇到的錯誤。
問題1:你如何解決這個問題? 如果可能的話,以下是我想要的。 test.c 文件中的兩個結構實際上存在於我的程序中。 游戲 function 正式版 arguments 也確實存在於我的真實世界程序中。 我的程序將整數*8 變量傳遞給游戲例程。 除了這三件事之外的其他一切都應該能夠被修改。
其他問題: C 代碼是否必須更改? 不算iso_c_binding接口代碼,Fortran代碼是不是要改? 有什么需要改變的?
iso_c_binding 可以做到這一點嗎?
謝謝,
文件 the_game.f
module the_game use, intrinsic :: iso_c_binding, only: c_int, c_float, c_ptr type, bind(c) :: myfloat real(c_float) :: float_tmp end type type, bind(c) :: myint integer(c_int) :: int_tmp end type interface function game(myint1, myfloat2) bind(c, name="game_") import :: c_int, c_ptr implicit none type(c_ptr) :: myint1 type(c_ptr) :: myfloat2 integer(c_int) :: game end function end interface end module the_game
文件 main.f:
program main use the_game integer*8 test_variable integer*8 test_variable2 integer ans ans=game (test_variable,test_variable2) end program main
文件test.c:
#include <stdio.h>
struct myfloat
{
float float_tmp;
};
struct myint
{
int int_tmp;
};
int game_(myint1,myfloat2)
struct myint **myint1;
struct myfloat **myfloat2;
{
/* printf ("(*myint1)->int_tmp = %d\n",(*myint1)->int_tmp); */
/* printf ("(*myfloat2)->float_tmp = %f\n",(*myfloat2)->float_tmp); */
/* (*myint1)->int_tmp = 1; */
/* (*myfloat2)->float_tmp = 100.1; */
return(0);
}
匯編:
gcc -g -c test.c -o test.o
gfortran -g -c the_game.f -o the_game.o
gfortran -g -c main.f -o main.o
gfortran -g main.o test.o -o main.exe -lgfortran
Output:
main.f:9.19:
ans=game (test_variable,test_variable2)
1
Error: Type mismatch in argument 'myint1' at (1); passed INTEGER(8) to TYPE(c_ptr)
備選方案 1:以下 main.f 不起作用:
參考: https://wiki.scorec.rpi.edu/wiki/Iso_c_binding
program main use the_game integer*8, allocatable, target :: test_variable1 integer*8, allocatable, target :: test_variable2 integer ans type(c_ptr) :: cptr1 type(c_ptr) :: cptr2 allocate (test_variable1) allocate (test_variable2) cptr1 = c_loc(test_variable1) cptr2 = c_loc(test_variable2) ans=game (cptr1,cptr2) end program main
Output:
main.f:14.17: cptr1 = c_loc(test_variable1) 1 Error: Can't convert REAL(4) to TYPE(c_ptr) at (1) main.f:15.17: cptr2 = c_loc(test_variable2) 1 Error: Can't convert REAL(4) to TYPE(c_ptr) at (1)
備選方案 2:取消注釋 test.c 時,以下 main.f 不起作用:
文件 main.f:
program main use the_game TYPE(c_ptr) test_variable TYPE(c_ptr) test_variable2 integer ans ans=game (test_variable,test_variable2) end program main
#include <stdio.h>
struct myfloat
{
float float_tmp;
};
struct myint
{
int int_tmp;
};
int game_(myint1,myfloat2)
struct myint **myint1;
struct myfloat **myfloat2;
{
/*printf ("(*myint1)->int_tmp = %d\n",(*myint1)->int_tmp);
printf ("(*myfloat2)->float_tmp = %f\n",(*myfloat2)->float_tmp);
(*myint1)->int_tmp = 1;
(*myfloat2)->float_tmp = 2.0;*/
return(0);
}
如果取消注釋 test.c 中的 4 個語句,則運行可執行文件:test.c 中的最后一條語句導致段錯誤:
Program received signal SIGSEGV: Segmentation fault - invalid memory reference. line 5: 3541 Segmentation fault ./main.exe
備選方案 3:對代碼的以下 main.f 更改不起作用:
文件 main.f:
program main use the_game integer*8 test_variable integer*8 test_variable2 integer ans type(c_ptr) :: cptr1 type(c_ptr) :: cptr2 cptr1=c_loc(test_variable1) cptr2=c_loc(test_variable2) test_variable1 = 90 test_variable2 = 1000 ans=game (cptr1,cptr2) end program main
匯編:
main.f:11.25: cptr1=c_loc(test_variable1) 1 Error: Can't convert REAL(4) to TYPE(c_ptr) at (1) main.f:12.26: cptr2=c_loc(test_variable2) 1 Error: Can't convert REAL(4) to TYPE(c_ptr) at (1)
備選方案 4:對代碼的以下 main.f 更改無法編譯:
program main use iso_c_binding use the_game TYPE(c_ptr) test_variable TYPE(c_ptr) test_variable2 integer*8 value1 integer*8 value2 integer ans test_variable=c_loc(value1) test_variable2=c_loc(value2) ans=game (test_variable,test_variable2) end program main
編譯錯誤:
main.f:12.31: test_variable=c_loc(value1) 1 Error: Parameter 'value1' to 'c_loc' at (1) must be either a TARGET or an associated pointer main.f:13.32: test_variable2=c_loc(value2) 1 Error: Parameter 'value2' to 'c_loc' at (1) must be either a TARGET or an associated pointer
錯誤:(1) 處的參數“test_variable”中的類型不匹配; 將 INTEGER(8) 傳遞給 TYPE(c_ptr)
是的, INTEGER(8)
是與TYPE(c_ptr)
不同的類型。 不允許將前一種類型的參數與后一種類型的子程序參數相關聯。
問題1:你如何解決這個問題? 如果可能的話,以下是我想要的。 test.c 文件中的兩個結構實際上存在於我的程序中。
test.c 中沒有任何結構對象。 有兩種結構類型聲明,但沒有證據表明這些類型的對象。 這是必然的,因為不清楚您期望在哪里實際定義任何此類對象,或者由誰分配。
游戲 function 正式版 arguments 也確實存在於我的真實世界程序中。
當然正式的 arguments 到game_()
function 是存在的。 他們在 function 的定義中的聲明是必需的。 但也許你在談論他們指向的對象?
我的程序將整數*8 變量傳遞給游戲例程。
至少你的編譯器可能不會抱怨。 參數是指針,而不是整數。 I would expect a C compiler to emit an analogous complaint when processing an attempt to call the game_()
function in C with arguments that were integers of any size. C 指針不是整數,在 C 和 Fortran 中都不是。
除了這三件事之外的其他一切都應該能夠被修改。
這里有很多噪音和不清晰,但我認為你真正想要的是
game_()
function, 您已經對integer*8
和integer(8)
(不一定是同一件事)給予了很多關注,但這些並不是工作的正確工具。 我懷疑您在 C 方面還使用了比需要或有用的更多級別的間接。
由於您使用的是 GNU 編譯器套件,因此您應該考慮閱讀其關於 Fortran / C 互操作性特性的文檔,這還不錯。
您至少有以下注意事項需要處理:
我認為你實際上使它變得比雙方都需要的更難。
您似乎確實整理出了可互操作的類型聲明。
C function 聲明似乎是另一回事。 我看不出有什么合理的理由讓你想要接收指向結構的雙指針,結果可能不是你想的那樣。 無論您希望 Fortran 代碼將單個結構與每個參數或它們的數組相關聯,您可能希望 C 端將參數聲明為單個指針。 另請注意,盡管您可以使用帶有下划線的 C function 名稱,但您不需要這樣做。 只需指定您在 Fortran 接口中選擇的任何名稱即可。
例子:
測試.c
#include <stdio.h>
struct myfloat {
float float_tmp;
};
struct myint {
int int_tmp;
};
int game_(struct myint *myint1, struct myfloat *myfloat2) {
puts("C says:");
printf ("myint1->int_tmp = %d\n", myint1->int_tmp);
printf ("myfloat2->float_tmp = %f\n", myfloat2->float_tmp);
myint1->int_tmp = 1;
myfloat2->float_tmp = 2.0;
return 0;
}
請特別注意,arguments 只使用了一級間接。
Fortran 接口也非常簡單:
the_game.f90
module the_game
use, intrinsic :: iso_c_binding, only: c_int, c_float, c_ptr
type, bind(c) :: myfloat
real(c_float) :: float_tmp
end type
type, bind(c) :: myint
integer(c_int) :: int_tmp
end type
interface
function game(myint1, myfloat2) bind(c, name="game_")
import :: c_int, myfloat, myint
implicit none
type(myint) :: myint1 ! not a pointer!
type(myfloat) :: myfloat2 ! not a pointer!
integer(c_int) :: game
end function
end interface
end module the_game
請注意,function 參數未定義為指針。 Fortran 默認會傳遞指針,因為它的默認調用 suibprogram 調用語義使用(大約)通過引用傳遞。 主要是當您想要按值傳遞時(正如您經常做的那樣,因為這些是 C 的語義),您需要在聲明的接口中做任何特殊的事情。
有了它,從 Fortran 中調用它並不難。 例子:
main.f90
program main
use the_game
type(myint) :: test_variable
type(myfloat) :: test_variable2
integer ans
test_variable%int_tmp = 7
test_variable2%float_tmp = 3.14
ans = game(test_variable,test_variable2)
write(*, *)
write(*, *) 'Fortran says:'
write(*, *) 'Result = ', ans, '; my int = ', test_variable%int_tmp, &
'; my_float = ', test_variable2%float_tmp
end program main
請注意,在調用 C integer
的 Fortran 代碼中既沒有任何c_ptr
也沒有任何對應的 integer Fortran 端僅根據(可互操作的)Fortran 派生類型工作。 這是 output,表明雙方都在訪問相同的對象:
$./main.exe C says: myint1->int_tmp = 7 myfloat2->float_tmp = 3.140000 Fortran says: Result = 0; my int = 1; my_float = 2.00000000
或者
后來的評論表明,也許您打算使用game_()
的參數將 C 指針傳回 Fortran 調用者,也許是指向動態分配空間的指針。 這也可以適應,在這種情況下,您必須處理c_ptr
,因為這就是 C 將發出的。 But you do have to take care with level of indirection -- Fortran will pass an object of type c_ptr
to C by reference , which C will receive as a double pointer.
一旦返回 C 指針值,Fortran 將使用c_f_pointer()
子例程將適當類型的 Fortran 指針與分配的空間相關聯。 例子:
alttest.c
#include <stdio.h>
#include <stdlib.h>
struct myfloat {
float float_tmp;
};
struct myint {
int int_tmp;
};
int game_(struct myint **myint1, struct myfloat **myfloat2) {
*myint1 = malloc(sizeof(**myint1));
*myfloat2 = malloc(sizeof(**myfloat2));
if (!*myint1 || !*myfloat2) {
return -1;
}
(*myint1)->int_tmp = 1;
(*myfloat2)->float_tmp = 2.0;
return 0;
}
the_game_alt.f90
module the_game_alt
use, intrinsic :: iso_c_binding, only: c_int, c_float, c_ptr
type, bind(c) :: myfloat
real(c_float) :: float_tmp
end type
type, bind(c) :: myint
integer(c_int) :: int_tmp
end type
interface
function game(myint1_p, myfloat2_p) bind(c, name="game_")
import :: c_int, c_ptr
implicit none
type(c_ptr), intent(out) :: myint1_p
nd in this case you do have to deal with `c_ptr` type(c_ptr), intent(out) :: myfloat2_p
integer(c_int) :: game
end function
end interface
end module the_game_alt
altmain.f90
program main
use the_game_alt
use, intrinsic :: iso_c_binding
type(myint), pointer :: intvar
type(myfloat), pointer :: floatvar
type(c_ptr) :: myint_ptr, myfloat_ptr
integer ans
ans = game(myint_ptr, myfloat_ptr)
if (ans .ne. 0) then
write(*, *) 'error: C returned ', ans
else
call c_f_pointer(myint_ptr, intvar)
call c_f_pointer(myfloat_ptr, floatvar)
write(*, *)
write(*, *) 'Fortran says:'
write(*, *) 'Result = ', ans, '; my int = ', intvar%int_tmp, &
'; my_float = ', floatvar%float_tmp
end if
end program main
程序 output:
$./altmain.exe Fortran says: Result = 0; my int = 1; my_float = 2.00000000
注意:
目前還不清楚你真正想要做什么。 實際上,可能需要與上述任何一種方法不同的東西。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.