gpt4 book ai didi

c++ - 将字符串从 Fortran 传递到 C/C++ 的正确方法

转载 作者:塔克拉玛干 更新时间:2023-11-03 01:50:44 24 4
gpt4 key购买 nike

我想将字符串从 Fortran 传递到 C/C++。这是我的 Fortran 代码:

subroutine zdplaskinGetSpeciesName(cstring, index) bind(C, name='zdplaskinGetSpeciesName')
use iso_c_binding
use ZDPlasKin
implicit none
integer, intent(in) :: index
CHARACTER(10), TARGET :: fstring = ''
TYPE(C_PTR) :: cstring
fstring = species_name(index+1)
cstring = c_loc(fstring)
end subroutine zdplaskinGetSpeciesName

ZDPlasKin 是一个具有species_name(i) 的模块。

extern "C" void zdplaskinGetSpeciesName(char* cstring[], size_t* index);
char* cstring[1];
size_t index = 1;
zdplaskinGetSpeciesName(cstring, &index);
string speciesName = string(cstring[0]);
cout << speciesName << endl;

此方法的输出似乎没问题。但是,我想修剪尾随空格(character(10) 提供额外的空间),以便我的 C++ 代码可以正确读取字符串。我尝试了另一种方式。

subroutine zdplaskinGetSpeciesName(cstring, index) bind(C, name='zdplaskinGetSpeciesName')
use iso_c_binding
use ZDPlasKin
implicit none
integer, intent(in) :: index
CHARACTER(:), allocatable, TARGET :: fstring
TYPE(C_PTR) :: cstring
fstring = trim(species_name(index+1))
cstring = c_loc(fstring)
end subroutine zdplaskinGetSpeciesName

但是这样我得到了一些奇怪的符号。


我想把事情做对,这样我以后就不用担心了。内存泄漏不是我想要的。所以我想我会尝试你建议的替代方法。我想我想知道的是我怎么知道我是否需要释放一个指针。这是我在 StackOverflow 上找到的另一个代码(尽管这个代码将 C++ 字符串传递给 Fortran。https://stackoverflow.com/a/30430656/721644)

你觉得这个可以用吗?或者可能存在内存泄漏。你也可以给我一些关于你建议的替代方式的提示吗?

最佳答案

许多其他问题都处理了这个的变体。为关闭搜索完全相同的拷贝可能没有希望,但我强烈建议您搜索并阅读这些问题和答案。

C 字符串以 null 结尾。如果要修剪它,只需将空字符放在正确的位置即可。实际上,您在第一个版本中根本不是空终止字符串,因此很容易出现缓冲区溢出。

但更糟糕的是,变量 fstring 只是函数的局部变量。永远不要将指针传递给局部变量。

所以,第一个版本真的应该是

subroutine zdplaskinGetSpeciesName(cstring, index) bind(C, name='zdplaskinGetSpeciesName')
use iso_c_binding
use ZDPlasKin
implicit none
integer, intent(in) :: index
CHARACTER(11), POINTER :: fstring
TYPE(C_PTR) :: cstring
allocate(fstring)
fstring = species_name(index+1)
fstring(11:11) = c_null_char
cstring = c_loc(fstring)
end subroutine zdplaskinGetSpeciesName

要修剪字符串,只需将空字符放在正确的位置

   integer :: len
...
len = len_trim(fstring)
fstring(len+1:len+1) = c_null_char

您还可以使用指向长度字符数组的指针,该数组的长度将匹配字符串的长度 + 1 或类似于第二种方法的延迟长度 (character(:)) 字符指针。请记住始终为空终止保留 1 个字符。

现在代码会有内存泄漏。要避免内存泄漏,必须从 Fortran 中释放字符串!因此,您必须创建一个特殊的子程序来释放这些指针。


另一种方法是从 C++ 传递一个指向缓冲区的指针,然后只用 Fortran 语言填充字符串。我实际上更喜欢那样。您可以在 C++ 中使它以 null 终止,只是确保不要让 Fortran 覆盖终止字符。

你可以试试:

subroutine zdplaskinGetSpeciesName(cstring, index) bind(C, name='zdplaskinGetSpeciesName')
use iso_c_binding
use ZDPlasKin
implicit none
integer, intent(in) :: index
TYPE(C_PTR), intent(in) :: cstring
CHARACTER(kind=C_CHAR), POINTER :: fstring(:)
integer :: i, c_len, name_len

c_len = c_strlen(cstring)
c_f_pointer(cstring, fstring, [c_len])

associate(name => species_name(index+1))
name_len = trim_len(name)
do i = 1, name_len
fstring(i) = name(i:i)
end do
fstring(name_len+1:name_len+1)
end do
end subroutine zdplaskinGetSpeciesName

未经测试。您有责任从 C++ 提供足够大的空终止缓冲区。 c_strlen 可以在 http://fortranwiki.org/fortran/show/c_interface_module 找到


要 100% 符合标准,您应该使用长度为 1 的字符数组 character(kind=c_char),但字符串很可能在实践中起作用。

关于c++ - 将字符串从 Fortran 传递到 C/C++ 的正确方法,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/45330436/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com