Fortran内存地址输出差异问题:为何loc结果有时有效有时为0
Fortran数组参数的loc输出差异与指针访问问题
代码与运行结果
$ cat whereis.F90 program whereisit integer, target :: a(100) integer, pointer :: b(:) print '("a is at 0x",Z8)', loc(a) call just_checking_1(a) call just_checking_2(a) b => a print '("b is at 0x",Z8)', loc(b) call just_checking_p(b) end program subroutine just_checking_1(a) integer :: a(*) !<-- 注意: a(*) print '("In just_checking_1 a is at 0x",Z8)', loc(a) end subroutine subroutine just_checking_2(a) integer :: a(:) !<-- 注意: a(:) print '("In just_checking_2 a is at 0x",Z8)', loc(a) end subroutine subroutine just_checking_p(b) integer, pointer, intent(in) :: b(:) print '("In just checking b is at 0x",Z8)', loc(b) end subroutine
运行输出:
$ ./a.out a is at 0x 6B4140 In just_checking_1 a is at 0x 6B4140 In just_checking_2 a is at 0x 0 b is at 0x 6B4140 In just checking b is at 0x 0
为什么just_checking_1和just_checking_2的输出不一样?
你的推测完全正确,核心就是假定大小数组(a(*))和假定形状数组(a(:))的底层传递机制不同:
假定大小数组
a(*):
这是Fortran传统的数组传递方式,编译器直接把原数组的起始内存地址传给子程序。所以loc(a)返回的就是主程序中数组a的实际起始地址,两者输出一致。它不携带数组的形状信息,需要额外手段(比如另一个参数)来确定数组大小。假定形状数组
a(:):
这种参数传递的是一个数组描述符,而非数组数据本身。描述符里存着数组的起始地址、维度、步长等元数据。此时loc(a)取的是这个描述符的内存地址,而非数组数据的地址。有些编译器会把描述符放在临时内存区域,甚至返回0(因为loc函数对描述符的行为没有标准化定义),这就是你看到输出0的原因。
简单总结:a(*)传的是数据地址,a(:)传的是管理数组的“元数据容器”地址,loc对两者的作用对象完全不同。
just_checking_p能访问指针b指向的内存吗?
完全可以,loc(b)输出0不代表指针无法访问目标内存:
- 子程序中的指针形参
b(:)传递的也是描述符,loc(b)取的是这个描述符的地址,不是指针指向的数据地址。但描述符里已经包含了指针目标的内存地址、形状等关键信息。 - 在子程序中,你可以正常使用
b来读写它指向的内存(比如执行print *, b(1)或者b(5)=99),不会有任何问题。 - 主程序中
loc(b)返回的是指针指向的数据地址,这是因为主程序里b是指针变量,loc作用于它时,语义是返回指针的目标地址;而子程序里b是指针形参,loc的作用对象变成了形参的描述符,两者语义不同而已。
内容的提问来源于stack exchange,提问作者bob.sacamento
相关产品推荐
相关产品推荐

