通过指针更改 intent(in) 变量
Changing intent(in) variables through a pointer
我想知道是否 legal/safe 通过与相应实际参数关联的指针修改 intent(in)
虚拟参数。具体是在调用子程序之前建立指针关联时。
例如,以下是否可以(它似乎可以与 gfortran 一起工作)?
program test
implicit none
type compound
integer, allocatable :: A1(:)
integer, pointer :: A2(:,:)
end type compound
type(compound), target :: my
integer :: n=5, i
allocate(my%A1(n**2))
my%A2(1:n,1:n) => my%A1(:)
do i=1,n**2
my%A1(i) = i
end do
do i=1,n
print *, my%A2(i,:)
end do
call assign_A(my)
do i=1,n
print *, my%A2(i,:)
end do
contains
subroutine assign_A(var)
type(compound), intent(in) :: var
var%A2(:,:) = 42
end subroutine
end program test
技巧是一个包含指针和目标的用户定义类型,前者指向后者。 this 的实例作为 intent(in)
传递,并在子例程中通过指针组件修改它(可以修改 intent(in)
指针指向的值)。我有点惊讶这会起作用,但也许这只是编译器缺少的诊断。如果我直接更改 var%A1
那当然会失败。
编辑:上述程序的输出(使用 gfortran 7.5.0 编译):
1 6 11 16 21
2 7 12 17 22
3 8 13 18 23
4 9 14 19 24
5 10 15 20 25
42 42 42 42 42
42 42 42 42 42
42 42 42 42 42
42 42 42 42 42
42 42 42 42 42
您不能以这种方式更改 intent(in)
对象的值。编译器不必(能够)告诉您您做错了什么。 (此外,对编译器的期望是它应该能够检测到所有进行非法更改的情况,这是不合理的期望。)
伪参数var
是一个非指针对象,这意味着它的组件也具有相同的意图属性。您正在尝试通过赋值 var%A2(:,:) = 42
定义 var
及其组件 var%A1
因为 var%A2
是与 my%A1
关联的指针(通过 [=11 的参数关联=] 与 my
);通过var
和[=18=的参数关联,my%A1
的定义就是var%A1
的定义。
这违反了(F2018 8.5.10 p2)的声明:
The INTENT (IN) attribute for a nonpointer dummy argument specifies that it shall neither be defined nor become undefined during the invocation and execution of the procedure.
但是,这不是编号约束或语法规则,因此不要求编译器能够 。如果要求编译器能够诊断更改 var
的违规情况,则在 (F2018 C844 (R826)):
A nonpointer object with the INTENT (IN) attribute shall not appear in a variable definition context (19.6.7).
一个变量定义上下文是特定的,问题的赋值语句不是var
或var%A1
的变量定义上下文。在变量定义上下文中,诸如 var%A1=42
(您注意到编译器抱怨)的赋值是 var%A1
(但不是 var
)的外观。
您可能还想知道别名限制是否起作用。
总而言之,可以使用 intent(in)
从编译器中隐藏对虚拟变量的更改。正如程序员不喜欢被欺骗一样,如果您这样做,您的编译器也不必仍然是您的朋友。编译器可以假定 var
在子例程期间不会更改值,如果您找到颠覆它的方法,它不会欠您任何东西。
我想知道是否 legal/safe 通过与相应实际参数关联的指针修改 intent(in)
虚拟参数。具体是在调用子程序之前建立指针关联时。
例如,以下是否可以(它似乎可以与 gfortran 一起工作)?
program test
implicit none
type compound
integer, allocatable :: A1(:)
integer, pointer :: A2(:,:)
end type compound
type(compound), target :: my
integer :: n=5, i
allocate(my%A1(n**2))
my%A2(1:n,1:n) => my%A1(:)
do i=1,n**2
my%A1(i) = i
end do
do i=1,n
print *, my%A2(i,:)
end do
call assign_A(my)
do i=1,n
print *, my%A2(i,:)
end do
contains
subroutine assign_A(var)
type(compound), intent(in) :: var
var%A2(:,:) = 42
end subroutine
end program test
技巧是一个包含指针和目标的用户定义类型,前者指向后者。 this 的实例作为 intent(in)
传递,并在子例程中通过指针组件修改它(可以修改 intent(in)
指针指向的值)。我有点惊讶这会起作用,但也许这只是编译器缺少的诊断。如果我直接更改 var%A1
那当然会失败。
编辑:上述程序的输出(使用 gfortran 7.5.0 编译):
1 6 11 16 21
2 7 12 17 22
3 8 13 18 23
4 9 14 19 24
5 10 15 20 25
42 42 42 42 42
42 42 42 42 42
42 42 42 42 42
42 42 42 42 42
42 42 42 42 42
您不能以这种方式更改 intent(in)
对象的值。编译器不必(能够)告诉您您做错了什么。 (此外,对编译器的期望是它应该能够检测到所有进行非法更改的情况,这是不合理的期望。)
伪参数var
是一个非指针对象,这意味着它的组件也具有相同的意图属性。您正在尝试通过赋值 var%A2(:,:) = 42
定义 var
及其组件 var%A1
因为 var%A2
是与 my%A1
关联的指针(通过 [=11 的参数关联=] 与 my
);通过var
和[=18=的参数关联,my%A1
的定义就是var%A1
的定义。
这违反了(F2018 8.5.10 p2)的声明:
The INTENT (IN) attribute for a nonpointer dummy argument specifies that it shall neither be defined nor become undefined during the invocation and execution of the procedure.
但是,这不是编号约束或语法规则,因此不要求编译器能够 var
的违规情况,则在 (F2018 C844 (R826)):
A nonpointer object with the INTENT (IN) attribute shall not appear in a variable definition context (19.6.7).
一个变量定义上下文是特定的,问题的赋值语句不是var
或var%A1
的变量定义上下文。在变量定义上下文中,诸如 var%A1=42
(您注意到编译器抱怨)的赋值是 var%A1
(但不是 var
)的外观。
您可能还想知道别名限制是否起作用。
总而言之,可以使用 intent(in)
从编译器中隐藏对虚拟变量的更改。正如程序员不喜欢被欺骗一样,如果您这样做,您的编译器也不必仍然是您的朋友。编译器可以假定 var
在子例程期间不会更改值,如果您找到颠覆它的方法,它不会欠您任何东西。