Warning: file_get_contents(/data/phpspider/zhask/data//catemap/5/fortran/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Fortran 将字符串内联传递给子例程调用(其中参数定义了长度),会产生意外结果_Fortran_Fortran95 - Fatal编程技术网

Fortran 将字符串内联传递给子例程调用(其中参数定义了长度),会产生意外结果

Fortran 将字符串内联传递给子例程调用(其中参数定义了长度),会产生意外结果,fortran,fortran95,Fortran,Fortran95,我发现这段代码的行为出人意料 module testmodule integer, parameter :: LCHARS = 50 contains subroutine init() call foobar("foobar") end subroutine subroutine foobar(s) character(len=*), intent(in) :: s call bar(s) end subroutine

我发现这段代码的行为出人意料

module testmodule
   integer, parameter :: LCHARS = 50
contains
   subroutine init()
      call foobar("foobar")
   end subroutine

   subroutine foobar(s)
      character(len=*), intent(in) :: s
      call bar(s)
   end subroutine

   subroutine bar(str)
      character(len=LCHARS), intent(in)  :: str

      print *, str
   end subroutine
end module

program foo
   use testmodule
   call init()
end program
此代码打印依赖于编译器的垃圾

我发现问题在于,对于字符串参数,我正在跳过一个带有
len=*
的例程,然后将该例程传递给一个具有指定长度的例程


引擎盖下到底发生了什么,在标准中描述了这种行为的地方?我是否应该避免为字符例程参数指定长度,因为这种行为可能在没有警告的情况下随时发生?

问题是
bar
需要长度为50的字符串(参见
character(len=LCHARS),intent(in)::str
),而传递它的字符串的长度仅为6。用

ifort-全部警告、nodec、接口、声明-gen_接口-全部检查-std test.f90

产生错误

forrtl:severe(408):fort:(18):虚拟字符变量'STR'的长度为50,大于实际变量长度6


据我们所知,所有Fortran参数都是通过引用传递的。在幕后,函数
bar
得到的是一个指向字符串
str
开头的指针和一个额外的参数,其值是字符串的长度。因此,
bar
将占用50个字符的内存,从
str
开头开始,并将其打印到屏幕上。由于您传递的字符串只有6个字符长,剩余的44个字符将是“foobar”之后的下一位内存中的任何字符,这将在运行时有所不同,或者取决于您使用的编译器。

参数传递取决于编译器,只要满足标准的要求,但通常是一个字符(len=*)伪参数的接口类似

void foo(字符*s,整数len)

在foo过程的实现中,隐藏的len参数用作字符串长度。OTOH,对于字符(len=somevalue)参数,隐藏的len参数要么被忽略,要么根本不传递,并且过程的代码假定somevalue是字符串的正确长度


正如您所看到的,除非您真的知道自己在做什么,并且可以引用标准中的章节来解释原因,否则您不应该使用LEN=*以外的任何东西。

我认为您的代码不符合要求。Fortran 95标准的
12.4.1.1节规定:

12.4.1.1与虚拟数据对象关联的实际参数
[…]
如果标量伪参数的类型为默认字符,则伪参数的长度len 应小于或等于实际参数的长度。伪参数变为 与实际参数最左边的len字符关联


您的速度更快了。这或多或少是正确的,但是Fortran参数不必通过引用传递,尽管对于字符串和数组,这是非常可能的。@VladimirF我假设Fortran标准没有指定参数的传递方式,这只是一个实现细节。但是,我假设对于认为它们是通过引用重新传递不会给您带来太多麻烦。如果您能澄清一下,请随意编辑我的答案。如果您不使用C链接或使用属性值(显然),这应该不会给您带来太多麻烦。我想你的答案很好。更详细地说,禁止给出指定的长度不是更好吗?关于长度的假设根本不能保证,因为代码不一定知道它提供的字符串的长度,编译器也不能总是捕捉到错误。@StefanoBorini:原因是历史。回到恐龙时代,LEN=*并不存在。但是当它被添加时,为了不破坏现有的代码,旧的方法仍然必须保留。