[英]passing char arrays from c++ to fortran
我无法将char数组从c ++传递给fortran(f90)。
这是我的c ++文件'cmain.cxx':
#include <iostream>
using namespace std;
extern "C" int ftest_( char (*string)[4] );
int main() {
char string[2][4];
strcpy(string[0],"abc");
strcpy(string[1],"xyz");
cout << "c++: string[0] = '" << string[0] << "'" << endl;
cout << "c++: string[1] = '" << string[1] << "'" << endl;
ftest_(string);
return 0;
}
这是我的fortran文件'ftest.f90':
SUBROUTINE FTEST(string)
CHARACTER*3 string(2)
CHARACTER*3 expected(2)
data expected(1)/'abc'/
data expected(2)/'xyz'/
DO i=1,2
WRITE(6,10) i,string(i)
10 FORMAT("fortran: string(",i1,") = '", a, "'" )
IF(string(i).eq.expected(i)) THEN
WRITE(6,20) string(i),expected(i)
20 FORMAT("'",a,"' equals '",a,"'")
ELSE
WRITE(6,30) string(i),expected(i)
30 FORMAT("'",a,"' does not equal '",a,"'")
END IF
ENDDO
RETURN
END
构建过程是:
gfortran -c -m64 ftest.f90
g++ -c cmain.cxx
gfortran -m64 -lstdc++ -gnofor_main -o test ftest.o cmain.o
编辑:请注意,可执行文件也可以通过以下方式构建:
g++ -lgfortran -o test ftest.o cmain.o
此外,因为我正在运行OSX 10.6,所以需要-m64标志。
执行'test'的输出是:
c++: string[0] = 'abc'
c++: string[1] = 'xyz'
fortran: string(1) = 'abc'
'abc' equals 'abc'
fortran: string(2) = 'xy'
'xy' does not equal 'xyz'
在ftest.f90中声明大小为4的'string'和'expected'字符数组,即:
CHARACTER*4 string(2)
CHARACTER*4 expected(2)
并重新编译提供以下输出:
c++: string[0] = 'abc'
c++: string[1] = 'xyz'
fortran: string(1) = 'abc'
'abc' does not equal 'abc '
fortran: string(2) = 'xyz'
'xyz' does not equal 'xyz '
在'cmain.cxx'中声明大小为3的字符数组,即:
extern "C" int ftest_( char (*string)[3] );
int main() {
char string[2][3];
并恢复到fortran文件中的原始大小(3),即:
CHARACTER*3 string(2)
CHARACTER*3 expected(2)
并重新编译提供以下输出:
c++: string[0] = 'abcxyz'
c++: string[1] = 'xyz'
fortran: string(1) = 'abc'
'abc' equals 'abc'
fortran: string(2) = 'xyz'
'xyz' equals 'xyz'
所以最后一种情况是唯一有效的情况,但在这里我已经为一个大小为3的字符数组分配了3个字符,这意味着缺少终止'\\ 0',并导致'abcxyz'输出 - 这是不可接受的我的预期申请。
任何帮助将不胜感激,这让我疯了!
C字符串是零终止的,而按照惯例,fortran字符串是空间填充但具有固定大小。 如果没有一些转换,你不应该期望能够将C字符串传递给fortran。
例如:
#include <algorithm>
void ConvertToFortran(char* fstring, std::size_t fstring_len,
const char* cstring)
{
std::size_t inlen = std::strlen(cstring);
std::size_t cpylen = std::min(inlen, fstring_len);
if (inlen > fstring_len)
{
// TODO: truncation error or warning
}
std::copy(cstring, cstring + cpylen, fstring);
std::fill(fstring + cpylen, fstring + fstring_len, ' ');
}
然后你可以使用3或4长度版本的ftest
:
#include <iostream>
#include <ostream>
extern "C" int ftest_( char string[][4] );
void ConvertToFortran(char* fstring, std::size_t fstring_len,
const char* cstring);
int main()
{
char cstring[2][4] = { "abc", "xyz" };
char string[2][4];
ConvertToFortran(string[0], sizeof string[0], cstring[0]);
ConvertToFortran(string[1], sizeof string[1], cstring[1]);
std::cout << "c++: string[0] = '" << cstring[0] << "'" << std::endl;
std::cout << "c++: string[1] = '" << cstring[1] << "'" << std::endl;
ftest_(string);
return 0;
}
我建议使用Fortran端的ISO C绑定,如“高性能标记”所示。 你已经在使用“extern C”了。 Fortran 2003的ISO C绑定(目前在大多数Fortran 95 /部分Fortan 2003编译器中实现)使这成为一种独立于编译器和平台的方法。 Charles Bailey描述了两种语言中字符串之间的差异。 这个Stackoverflow问题有一个代码示例: 从C调用FORTRAN子例程
如果您不想修改现有的Fortran代码,可以在C ++代码和现有的Fortran代码之间编写一个“粘合”例程。 使用ISO C Binding在Fortran中编写胶水例程将更加可靠和稳定,因为这将基于语言标准的特征。
给出的例子太重了,只要你不想传递多个字符串就可以使用“隐藏”长度参数......
extern "C" void function_( const char* s, size_t len ) {
std::string some_string( s, 0, len );
/// do your stuff here ...
std::cout << "using string " << some_string << std::endl;
/// ...
}
你可以从fortran那里打来电话
call function( "some string or other" )
您不需要对单个复制操作进行操作,因为std :: string构造函数可以为您完成所有这些操作。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.