我无法将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'输出 - 这是我的预期申请不可接受。
任何帮助将不胜感激,这让我疯狂!
答案 0 :(得分:10)
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;
}
答案 1 :(得分:5)
我建议按照“高性能标记”的建议在Fortran端使用ISO C Binding。你已经在使用“extern C”了。 Fortran 2003的ISO C绑定(目前在大多数Fortran 95 /部分Fortan 2003编译器中实现)使这成为一种独立于编译器和平台的方法。 Charles Bailey描述了两种语言中字符串之间的差异。此Stackoverflow问题有一个代码示例:Calling a FORTRAN subroutine from C
如果您不想修改现有的Fortran代码,可以在C ++代码和现有的Fortran代码之间编写一个“粘合”例程。使用ISO C Binding在Fortran中编写胶水例程将更加可靠和稳定,因为这将基于语言标准的特性。
答案 2 :(得分:1)
给出的例子太重要了,只要你不想传递多个字符串就可以使用&#34; hidden&#34;长度参数...
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构造函数可以为你完成所有这些操作。