从fortran传递到c的字符串上的额外内容是什么?如何停止它?

从fortran传递到c的字符串上的额外内容是什么?如何停止它?,c,fortran,C,Fortran,我试图将一个字符串和一个值从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

我试图将一个字符串和一个值从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);
}
fortran
整数rmat
rmat=4
呼叫cprint(“rmat”,rmat)
结束
cprint_uuc
#包括
void cprint_(字符*字符串,int*wtf,int*var){
printf(“字符串:%s wtf:%s变量:%d\n”,字符串,wtf,变量);
}
输出:
string:rmat convertedtest.f wtf:var:5

您正在尝试使用
%s
格式设置程序打印
int*
,该格式设置程序保留字符串

您必须使用
%d
,并且不要忘记指针中的
wtf
,因此您必须使用
*wtf
取消对它的引用Fortran字符串相当于固定长度字符数组。语义上,它们不是以null结尾的。相反,由实现来跟踪它们的长度。历史上,实现通过各种不同的方法通过函数调用跟踪字符串长度,但最常见的方法可能是将长度作为一个附加的隐式参数传递。那肯定是你看到的

在某些实现中,额外的参数紧跟在字符串后面,而在其他实现中,所有字符串长度都位于参数列表的末尾。但是,与直接对应于对象的参数不同,长度参数通常是整数,而不是指针

您的测试虽然在技术上存在错误,但强烈表明字符串长度作为第三个参数传递(实际上是作为
int
,而不是
int*
)。因此,在适当的
cprint\uu
函数处的第一次切割可能如下所示:

void cprint_(char *string, int *integer, int string_len) {
    printf("string: '%.*s'\ninteger: %d\n", string, string_len, *integer);
}
如果要打印从Fortran收到的字符串,而不进行修改,那么可以指定适当的精度,如图所示,因为不能假定字符串已终止。但是,实际上,您可能希望打印的字符串的字符数少于其实际长度,因为数组的大小和其中有意义的字符数之间没有明确的区别。当分配给Fortran字符串的值小于其大小时,Fortran字符串用空格(
“”
)右填充,Fortran程序通常假定实际数据仅扩展到最后一个非空白字符


但是要小心:如果您通过插入C字符串终止符来修改字符串,那么您也在更改Fortran端的数据。如果你必须复制,但通常你可以避免这样做,就像上面的例子那样。

由@John Bollinger提供的答案是正确的。Fortran对字符串的处理与C完全不同。这是我几天前编写的一个示例代码,它将字符数组从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-2003字符串互操作方法是将Fortran字符串声明为字符数组,并将数组的长度从C显式传递到Fortran,反之亦然,如上面的示例所示。请注意,所有分配都发生在C端。Fortran 2018提供了在Fortran和C之间传递字符串(包括可分配字符串)的更为方便的方法,其中一些方法要求对Fortran代码进行无更改,并通过
ISO_Fortran_binding.h
对C代码进行最少的操作。例如,请参见。

wtf
int*
,不应使用
%s
打印。您将
int*wtf
视为一个带有
%s
的字符串。另外,
var
是不正确的类型。我认为您需要类似于
printf的东西(“字符串:%s wtf:%d var:%d\n”,字符串,*wtf,*var)没有关于Fortran端的评论(我不知道),但调用
cprint
时仅使用两个参数似乎有点可疑。由于您没有使用Fortran 2003的标准化互操作性功能,请说明您使用的编译器(包括版本)。例如,许多编译器在使用带有字符参数的C函数时会传递额外的长度argunet。
#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;
}
$ 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!