2012-04-15 43 views
6

Tôi gặp sự cố khi truyền mảng char từ C++ đến fortran (f90).truyền mảng char từ C++ đến fortran

Đây là c của tôi ++ file, 'cmain.cxx':

Đây là tập tin fortran tôi, '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 

Quá trình xây dựng là:

gfortran -c -m64 ftest.f90 
g++ -c cmain.cxx 
gfortran -m64 -lstdc++ -gnofor_main -o test ftest.o cmain.o 

Chỉnh sửa: lưu ý rằng tệp thi hành cũng có thể được tạo thông qua:

g++ -lgfortran -o test ftest.o cmain.o 

Ngoài ra, cờ -m64 là bắt buộc khi tôi chạy OSX 10.6.

Kết quả từ thực hiện 'test' là:

c++: string[0] = 'abc' 
c++: string[1] = 'xyz' 
fortran: string(1) = 'abc' 
'abc' equals 'abc' 
fortran: string(2) = 'xy' 
'xy' does not equal 'xyz' 

Tuyên bố 'string' và 'dự kiến' mảng nhân vật trong ftest.f90 với kích thước 4, ví dụ:

CHARACTER*4 string(2) 
CHARACTER*4 expected(2) 

và biên dịch lại cung cấp kết quả sau:

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 ' 

Khai báo mảng ký tự trong 'cmain.cxx' với kích thước 3, ví dụ:

extern "C" int ftest_(char (*string)[3]); 

int main() { 
    char string[2][3]; 

và quay trở lại kích thước ban đầu trong file fortran (3), ví dụ:

CHARACTER*3 string(2) 
CHARACTER*3 expected(2) 

và biên dịch lại cho kết quả như sau:

c++: string[0] = 'abcxyz' 
c++: string[1] = 'xyz' 
fortran: string(1) = 'abc' 
'abc' equals 'abc' 
fortran: string(2) = 'xyz' 
'xyz' equals 'xyz' 

Vì vậy, trường hợp cuối cùng là chỉ có một mà làm việc, nhưng ở đây tôi đã chỉ định 3 ký tự cho một mảng char kích thước 3 có nghĩa là chấm dứt '\ 0' là mất tích, và dẫn đến đầu ra 'abcxyz' - điều này là không thể chấp nhận cho ứng dụng dự định của tôi.

Bất kỳ trợ giúp nào sẽ được đánh giá rất nhiều, điều này đang thúc đẩy tôi hạt!

+0

Tôi không thấy dấu hiệu cho thấy bạn đang sử dụng các khả năng 'Khả năng tương tác với C' của Fortran được thiết kế để giảm bớt các vấn đề như bạn đang gặp phải. Tôi đề nghị bạn sử dụng chúng. –

+0

Hi Mark, tôi có một chương trình fortran được cung cấp bên ngoài mà tôi muốn giao tiếp với thông qua C++. Tôi không thể sửa đổi mã fortran. Bạn có thể thấy một cách để làm việc này mà không sửa đổi tệp fortran gốc không? – user1334640

+0

Nó phụ thuộc vào loại giao tiếp thực tế bạn đang làm, nhưng nếu bạn có mã Fortran, ngay cả khi bạn không thể thay đổi nó, bạn có thể thêm một mô-đun giao diện C vào nó. Mô-đun sẽ chỉ làm cho một số chức năng chuyển đổi hiển thị thành C. Là phần thưởng, bạn có thể loại bỏ dấu _ ở các tên hàm. –

Trả lời

10

Chuỗi C không được kết thúc trong khi chuỗi trtran, theo quy ước, là khoảng trống nhưng có kích thước cố định. Bạn không nên mong đợi để có thể vượt qua chuỗi C để fortran mà không cần một số chuyển đổi.

Ví dụ:

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

nào thì bạn có thể sử dụng với một trong hai 3 hoặc 4 phiên bản chiều dài của 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; 
} 
5

tôi khuyên bạn nên sử dụng các tiêu chuẩn ISO C Ràng buộc về phía Fortran như đề xuất bởi "Hiệu suất cao Mark". Bạn đã sử dụng "extern C". Liên kết ISO C của Fortran 2003 (hiện được triển khai trong hầu hết các trình biên dịch Fortan 95/một phần của Fortan 2003) làm cho phương pháp này trở thành một trình biên dịch độc lập và nền tảng. Charles Bailey mô tả sự khác biệt giữa các chuỗi trong hai ngôn ngữ.Câu hỏi Stackoverflow này có ví dụ về mã: Calling a FORTRAN subroutine from C

Nếu bạn không muốn sửa đổi mã Fortran hiện tại, bạn có thể viết thói quen "keo" ở giữa mã C++ và mã Fortran hiện tại. Viết thói quen keo ở Fortran bằng cách sử dụng ISO C Binding sẽ đáng tin cậy hơn và ổn định vì điều này sẽ dựa trên các tính năng của một tiêu chuẩn ngôn ngữ.

1

Các ví dụ đưa ra là quá nặng, miễn là bạn không muốn để vượt qua nhiều hơn một chuỗi, bạn có thể tận dụng các tham số chiều dài "ẩn" ...

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; 
    /// ... 

} 

mà bạn có thể gọi từ fortran như

call function("some string or other") 

Bạn không cần phải lo lắng về các thao tác sao chép riêng lẻ, vì trình tạo chuỗi std :: có thể làm tất cả những gì cho bạn.

+1

Có lẽ chúng là nặng (nhưng nó không phải là ý kiến ​​của tôi, thêm 'bind (C)' là đơn giản), nhưng chúng là di động. Không có gì trong tiêu chuẩn Fortran nói rằng biểu tượng hàm sẽ là tên có dấu gạch dưới và không có gì đảm bảo kiểu đối số ẩn và vị trí của nó trong danh sách đối số. Thậm chí không có đảm bảo có bất kỳ đối số ẩn nào. –

+0

Cảm ơn, mặc dù ví dụ về trình bao bọc fortran cần phải viết, ví dụ http://stackoverflow.com/questions/8207997/calling-a-fortran-subroutine-from-c/8208960 phức tạp hơn nhiều so với ví dụ 3 dòng của tôi, vì vậy tôi sẽ gắn bó với cách tiếp cận của tôi. –