2012-04-15 131 views
6

我在将char数组从C++传递到fortran(f90)时遇到了问题。将字符数组从C++传递到fortran

这里是我的C++文件, 'cmain.cxx':

这里是我的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标志。

从执行 '测试' 的输出是:

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,即:

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 ' 

与大小3中声明 'cmain.cxx' 的字符阵列,即:

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

我没有看到您正在使用Fortran的'与C的互操作性'功能,旨在缓解您面临的这些问题。我建议你使用它们。 – 2012-04-15 16:22:27

+0

嗨,马克,我有一个外部提供的fortran程序,我希望通过C++进行接口。我无法修改Fortran代码。你能否看到一种方法让这个工作不需要修改原始的fortran文件? – user1334640 2012-04-15 16:34:24

+0

这取决于您正在进行的接口连接的实际类型,但是如果您拥有Fortran代码,即使无法更改它,也可以向其添加C接口模块。这个模块只会让一些转换函数对C可见。作为奖励,您可以去掉函数名称中的尾部_。 – 2012-04-15 17:47:12

回答

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, ' '); 
} 

,然后可以用ftest或者3或4长度版本使用:

#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; 
} 
5

我建议使用ISO C绑定上的Fortran侧的建议通过“高性能标志”。你已经在使用“extern C”了。 Fortran 2003的ISO C绑定(目前在大多数Fortran 95 /部分Fortan 2003编译器中实现)使其成为一种独立于编译器和平台的方法。 Charles Bailey描述了两种语言中字符串之间的区别。这个Stackoverflow的问题有一个代码示例:Calling a FORTRAN subroutine from C

如果你不想修改现有的Fortran代码,你可以在C++代码和现有的Fortran代码之间编写一个“粘合”例程。使用ISO C绑定在Fortran中编写胶水例程将更加可靠和稳定,因为这将基于语言标准的特性。

1

给出的例子是太多重量级的,只要你不想传递多个字符串,你可以使用“隐藏”的长度参数...

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") 

你并不需要单独的拷贝操作faff有关,因为的std :: string构造函数可以做的一切,为你。

+1

也许他们是重量级的(但它不是我的意见,添加'bind(C)'很简单),但它们是可移植的。 Fortran标准中没有任何内容表示函数符号将是带下划线的名称,并且没有任何内容保证隐藏参数的类型及其在参数列表中的位置。甚至没有保证有任何隐藏的论点。 – 2015-09-21 09:09:15

+0

谢谢,尽管Fortran包装器需要写入例如http://stackoverflow.com/questions/8207997/calling-a-fortran-subroutine-from-c/8208960比我的3行示例复杂得多,所以我会坚持我的方法。 – 2015-09-22 09:45:21