我手边有以下程序
program foo
type bar
real, dimension(2) :: vector
end type
type(bar), dimension(3) :: bararray
call doSomething(bararray%vector)
end program
subroutine doSomething(v)
real, dimension(3,2), intent(inout) :: v
...
end subroutine
现在这给了我一个编译错误。
Error: Two or more part references with nonzero rank must not be specified at (1)
如果我将通话更改为
call doSomething((/bararray%vector(1), bararray%vector(2)/))
一切顺利。问题是,这看起来有点麻烦,所以问题是,是否还有其他方法可以为子程序编写参数?
提前致谢。
答案 0 :(得分:6)
出现错误是因为在语言中存在约束(在F2008中语法规则是C618),结构组件(或类似的多部分引用)中只有一部分可能具有非零等级。您对结构组件的引用bararray%vector
包含两个非零排名的部分 - 组件vector
和变量bararray
。
(在“更改调用”方法中,对组件向量的引用具有下标,该下标为该部分提供整体排名为零,因此接受bararray%vector(1)。)
“改变呼叫”方法存在重大潜在问题。
子程序中的伪参数是INTENT(INOUT)
。这需要实际的论证是可定义的(一个实际上可以“改变”的变量)。
在“更改调用”方法中,与该伪参数关联的实际参数是表达式 - 数组构造函数。表达式是不可定义的 - 评估它们的结果是一个值而不是可以“定义”的东西 - 即你不能理智地说2 + 2 = 6
。
据推测,在实际代码中,doSomething子例程是一个外部过程,因此您的编译器尚未对此进行诊断。如果doSomething有一个显式接口(因为它可能在一个模块中),那么我希望编译器报告错误。
其他人建议在调用之前重新编组数据的方法(将数据复制到适当大小的数组变量中,调用过程,将数据复制出来)。重写子程序的接口以获取bar类型的对象(移动到模块的类型的定义)显然是另一种可能性。派生类型不仅是存储数据的便捷方式,它们通常是处理数据的便捷方式。
我会非常警惕尝试欺骗处理器接受你“知道”内存中假设数组bararray%vector
的布局的方法。类型和数组的布局可以在处理器之间变化,加上处理器错误检查可以改善这种技巧,可能导致以后的诊断。供应商提供的库可以摆脱这种伎俩,但不仅仅是编程凡人。
答案 1 :(得分:5)
Intel Fortran(13.0.xxx)编译器提供错误
error #6159: A component cannot be an array if the encompassing structure is an array.
我觉得你的问题的答案是,调用一个带有real, dimension(3,2)
参数的子程序的正确方法是给该死的东西一个real, dimension(3,2)
参数,这需要编组你的数据在调用子程序之前的某种方式。是的,这有点麻烦,但不是严格的类型检查有一个很好的功能吗?
您可以沿着这些行定义包装器子例程:
subroutine wrapDoSomething(abar)
type(bar), dimension(:), intent(inout) :: abar
...
... marshal your data ...
call subroutine doSomething(marshalled_data)
...
end subroutine wrapDoSomething
我怀疑如果你在没有显式接口的情况下定义subroutine doSomething
,你可能会放弃传递它,调用者认为是bar
的数组,但子程序作为rank-2数组获得的是什么real
的。{如果这不能直接使用块,可能在类型定义上使用BIND(C)
,这可能会欺骗编译器为6个实数分配连续存储。
如果这一切都在你的脸上爆炸,你就是你自己,我将不会参与这项任务。