我从这个答案(Fortran copy of pointer)中了解到,我应该尝试使用可分配数组而不是数组指针作为派生类型的组件。我打算这样做但是我已经锁定了我当前的代码,并且需要能够使用它并理解它,直到明年我能做出更大更好的改变。
我也认为这个问题有一些普遍的兴趣,因为我觉得这里的fortran行为虽然显然是正确的但是非常不直观。因此,更好地理解它的工作原理和原因可能是有价值的(或者我认为编译器根本不会让我们这样做,对吧?)。
对于长篇介绍感到抱歉。我会尝试将这个作为一个注释程序尽可能地减少:
program main
type tRet
real :: agi
real :: wages_tgt(5) ! compiler won't let me declare as
! target but later I point to this
real, pointer :: wages(:)
end type tRet
type(tRet), target :: ret ! I don't quite understand
type(tRet), target :: orig1, orig2 ! why but compiler insists
! these be targets
ret%wages => ret%wages_tgt(1:1)
ret%wages = (/ 11. /)
orig1 = ret
ret%wages = (/ 99. /)
orig2 = ret
这是程序的上半部分,这里有一些结果,打印输出显示为右边的注释:
! This is not want I want and I was surprised, but it is kind
! of explained in the other answer why this happens, so OK...
print *, "orig1%wages ", orig1%wages ! 99.
print *, "orig2%wages ", orig2%wages ! 99.
! But if I copy from orig1 or orig2 into ret then it
! works like I wanted it to work in the first place!
! But I don't completely understand why it works...
ret = orig1
print *, "ret%wages ", ret%wages ! 11.
print *, "orig1%wages ", orig1%wages ! 11.
print *, "orig2%wages ", orig2%wages ! 11.
ret = orig2
print *, "ret = orig2 "
print *, "ret%wages ", ret%wages ! 99.
print *, "orig1%wages ", orig1%wages ! 99.
print *, "orig2%wages ", orig2%wages ! 99.
end program main
我很高兴能对这里发生的事情做出任何好的解释。我想,这里具有讽刺意味的是,我并不担心为什么这是一个坏主意,而是为什么我的解决方法似乎工作得很好?
或者总结一下我的问题最简单的方法是:究竟是什么指向什么?
编译器:GNU Fortran(GCC)4.8.5 20150623(Red Hat 4.8.5-16)
答案 0 :(得分:1)
这里发生的是,当您复制派生数据类型时,派生类型的每个组件都会发生不同的事情。当你orig1 = ret
时:
wages_tgt
)分配新值。这相当于说orig1%wages_tgt = ret%wages_tgt
。这些阵列中的每一个都占据内存中单独的位置。wages
)指向源指针当前指向的位置。这相当于说orig1%wages => ret%wages
。这两个指针的目标是内存中的相同位置。在此示例中,任何wages
指向的内存中唯一的位置是ret%wages_tgt
。考虑到这一点,你的结果对我有意义。添加一些选择性附加注释:
ret%wages => ret%wages_tgt(1:1)
ret%wages = (/ 11. /) ! so wages_tgt = 11 also
orig1 = ret ! This is BOTH a copy and re-point
! * orig1%wages_tgt = ret%wages_tgt (11)
! * orig1%wages => ret%wages_tgt
ret%wages = (/ 99. /) ! this changes ret%wages & ret%wages_tgt
! to 99 and also orig1%wages since it is
! also pointing to ret%wages_tgt.
! note that orig1%wages_tgt is UNCHANGED
! (still 11) but nothing is pointing to it!
降低代码......
ret = orig1 ! ret%wages_tgt = orig1%wages_tgt (11)
! no repointing actually happens this time b/c we have
! set up a circular relationship between all the
! pointers such that ALL of them point to ret%wages_tgt
答案 1 :(得分:0)
这是我在这里提出的问题的一个额外答案,但并没有明确说明。关于fortran如何在IMO工作的令人困惑的方面是你最终得到了导致不直观行为的圆形指针(即使根据f90规范它是正确的)。
但是明确地从SELECT (SELECT DATEDIFF('2018-02-20', '2018-02-14')) - (SELECT COUNT(id) FROM tbl_holiday WHERE dates BETWEEN '2018-02-14' AND '2018-02-20');
指向orig1%wages
(类似于orig1%wages_tgt
)你可以避免使用圆形指针,至少在某种程度上如此。这是与问题中相同的代码,但添加了一些明确的指向。
orig2
因此,保持ret%wages => ret%wages_tgt(1:1)
ret%wages = (/ 11. /)
orig1 = ret
orig1%wages => orig1%wages_tgt(:size(ret%wages)) ! *** added code ***
ret%wages = (/ 99. /)
orig2 = ret
orig2%wages => orig2%wages_tgt(:size(ret%wages)) ! *** added code ***
print *, "orig1%wages ", orig1%wages ! 11.
print *, "orig2%wages ", orig2%wages ! 99.
ret = orig1
print *, "ret%wages ", ret%wages ! 11.
print *, "orig1%wages ", orig1%wages ! 11.
print *, "orig2%wages ", orig2%wages ! 99.
ret = orig2
print *, "ret = orig2 "
print *, "ret%wages ", ret%wages ! 99.
print *, "orig1%wages ", orig1%wages ! 11.
print *, "orig2%wages ", orig2%wages ! 99.
& orig1
指针不同(并避免使用圆形指向),您可以将orig2
复制到orig1
,而不会产生更改ret
的副作用。
然而,遗憾的是,如果我使用关联进行测试,它声称orig2
并未指向orig1
,即使我明确指出这种方式并且行为似乎也反映出来的是:
orig2