簡體   English   中英

從fortran傳遞到c的字符串的額外內容是什么以及如何阻止它?

[英]What is the extra content on the string passed from fortran to c and how to stop it?

我試圖將一個字符串和一個值從fortran傳遞給c,它給了我奇怪的結果,我無法弄清楚發生了什么。

fortran      
      integer rmat

      rmat = 4
      call cprint("rmat ", rmat)

      END

cprint_.c

#include <stdio.h>

void cprint_( char *string, int *wtf, int *var){
    printf("string: %s wtf: %s var: %d\n", string, wtf, var);
}

輸出:

string:rmat convertedtest.f wtf:var:5

Fortran字符串相當於固定長度的字符數組。 從語義上講,它們不是以空值終止的。 相反,由實現來跟蹤它們的長度。 從歷史上看,實現通過各種不同的方式通過函數調用來跟蹤字符串長度,但最常見的可能是將長度作為附加的隱式參數傳遞。 那肯定是你所看到的。

在一些實現中,額外參數緊跟在字符串之后,而在其他實現中,所有字符串長度都在參數列表的末尾。 但是,通常,長度參數是整數,而不是指針,與直接對應於對象的參數不同。

您的測試雖然技術上不正確,但強烈建議您將字符串長度作為第三個參數傳遞(實際上是作為int ,而不是int * )。 因此,適當的cprint_函數的第一次剪切可能如下所示:

void cprint_(char *string, int *integer, int string_len) {
    printf("string: '%.*s'\ninteger: %d\n", string, string_len, *integer);
}

如果您要打印從Fortran接收的字符串而不進行修改,則指定合適的精度是合適的,如圖所示,因為不能假定該字符串被終止。 實際上,您可能希望打印字符串的字符數少於其實際長度,但是,因為數組的大小與其中有意義的字符數沒有明確的區別。 當為其分配小於其大小的值時,Fortran字符串右邊填充空格( ' ' ),並且Fortran程序通常假設實際數據僅擴展到最后一個非空字符。

但要小心:例如,如果通過插入C字符串終止符來修改字符串,那么您也將更改Fortran端的數據。 如果必須,請復制,但通常可以避免這樣做,如上例所示。

@John Bollinger提供的答案是正確的。 Fortran完全不同於C語言處理字符串。這是我幾天前編寫的一個示例代碼,它將一個char數組從C傳遞給Fortran,然后Fortran將其作為小寫並將結果返回給C,

module String_mod
    implicit none
contains
    subroutine getLowerCase(StrVec,StrVecLowerCase,lenStrVec) bind(C, name="getLowerCase")
        use, intrinsic :: iso_c_binding, only: c_char, c_null_char, c_size_t
        use, intrinsic :: iso_fortran_env, only: IK => int32
        integer(c_size_t), intent(in), value        :: lenStrVec
        character(len=1,kind=C_char), intent(in)    :: StrVec(lenStrVec)
        character(len=1,kind=C_char), intent(inout) :: StrVecLowerCase(lenStrVec)
        integer(IK), parameter                      :: duc = ichar('A') - ichar('a')
        character                                   :: ch
        integer(IK)                                 :: i
        write(*,"(*(g0))") "From Inside Fortran@getLowerCase(): StrVec = ", (StrVec(i),i=1,lenStrVec)
        write(*,"(*(g0))") "From Inside Fortran@getLowerCase(): lenStrVec = ", lenStrVec
        do i = 1, lenStrVec
            ch = StrVec(i)
            if (ch>='A' .and. ch<='Z') ch = char(ichar(ch)-duc)
            StrVecLowerCase(i) = ch
        end do
    end subroutine getLowerCase
end module String_mod

這是調用Fortran的C代碼,

#include <stdio.h>

// Fortran function's prototype
extern void getLowerCase(char [], char [], size_t );

int main(void)
{
    char StrVec[] = "HELLO FORTRAN! YOU ROCK!";
    size_t lenStrVec = sizeof(StrVec) / sizeof(StrVec[0]);
    char StrVecLowerCase[ lenStrVec ];

    getLowerCase( StrVec
                , StrVecLowerCase
                , lenStrVec
                );
    printf("From Inside C: %s\n", StrVecLowerCase);
    return 0;
}

使用英特爾Fortran / C編譯器進行編譯,

$ ifort -c String_mod.f90
$ icl -c main.c
$ icl String_mod.obj main.obj -o a.exe 
$ a.exe

From Inside Fortran@getLowerCase(): StrVec = HELLO FORTRAN! YOU ROCK!
From Inside Fortran@getLowerCase(): lenStrVec = 25
From Inside C: hello fortran! you rock!

最簡單的Fortran-2003字符串互操作方法是將Fortran字符串聲明為char數組,並將數組的長度從C顯式傳遞給Fortran,反之亦然,如上例所示。 請注意,所有分配都發生在C端。 Fortran 2018提供了更方便的方法來在Fortran和C之間傳遞字符串(包括可分配字符串),其中一些不需要更改 Fortran代碼, 也不需要通過ISO_Fortran_binding.h對C代碼進行最少的工作。 例如,請參閱此頁面

您正在嘗試使用%s格式化程序打印int * ,該格式化程序是字符串保留的。
你必須使用%d ,並且不要忘記指針中的wtf ,所以你必須用*wtf取消引用它

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM