重置(解除分配/无效)已损坏的Fortran可分配数组



当出现错误fortran错误中描述的情况时:已分配可分配数组;DEALLOCATE指向一个无法解除分配的数组(损坏的内存会留下一个看起来已分配但没有"指向"有效地址的可分配数组(,在Fortran中有什么可以解决的方法吗?即,将数组重置为解除分配,而不尝试解除分配它所指向的内存?

这种情况是在Fortran/C程序中,一段C代码故意破坏(向其中写入垃圾(分配的内存。这适用于普通类型的数组。但是,对于用户定义类型的可分配数组,它本身包括一个可分配组件,写入属于可分配组件的部分的垃圾意味着现在该组件显示为已分配,即使它不是。与其让C代码知道它应该损坏或不应该损坏什么,我更愿意在之后修复它,但是";使"无效";可分配的组件,当我知道我不在乎它当前指向的内存时。有了指针,这只是nullify的问题,但有了可分配的数组?

如果内存真的像堆栈内损坏/堆损坏一样损坏。你什么都做不了。这个程序一定会失败,因为非常低级的信息丢失了。任何编程语言都是如此,即使是C.

如果损坏的是Fortran数组描述符,则无法从Fortran中更正它。Fortran不会向Fortran程序员公开这些实现细节。它只能通过来自C.的名为ISO_Fortran_binding.h的特殊标头使用

如果发生的唯一损坏是使Fortran将数组分配到不分配的地方,那么从C恢复它应该相当简单。所需要的只是更改分配内存的地址。可分配数组总是连续的。

也可以尝试一些肮脏的技巧,比如告诉子例程你传递的是一个指针,而实际上它是一个可分配的指针,并将其无效。这可能在许多实现中都有效。但以可控的方式取消地址要干净得多。即使它只是您从Fortran调用的一个使C函数无效的函数。

因为您确实只想将地址更改为0,而不想对数组范围、步长和其他细节进行任何其他特殊处理,所以即使没有标头,也应该很简单。

请注意,描述符仍然会在其他变量中包含无意义的数据,但这些数据应该无关紧要。


这是一个快速而肮脏的测试:

Fortran:

dimension A(:,:)
allocatable A

interface
subroutine write_garbage(A) bind(C)
dimension A(:,:)
allocatable A
end subroutine

subroutine c_null_alloc(A) bind(C)
dimension A(:,:)
allocatable A
end subroutine

end interface

call write_garbage(A)

print *, allocated(A)

call c_null_alloc(A)

print *, allocated(A)

end

C:

#include <stdint.h>
void write_garbage(intptr_t* A){
*A = 999;
}
void c_null_alloc(intptr_t* A){
*A = 0;
}

结果:

> gfortran c_allocatables.c c_allocatables.f90
> ./a.out 
T
F

如果编译器提供了ISO_Fortran_binding.h,那么一个合适的版本应该使用它。还有implicit none和其他无聊的东西。。。


一个非常肮脏(和非法(的黑客,我根本不建议:

dimension A(:,:)
allocatable A

interface
subroutine write_garbage(A) bind(C)
dimension A(:,:)
allocatable A
end subroutine

subroutine null_alloc(A) bind(C)
dimension A(:,:)
allocatable A
end subroutine

end interface

call write_garbage(A)

print *, allocated(A)

call null_alloc(A)

print *, allocated(A)

end
subroutine null_alloc(A) bind(C)
dimension A(:,:)
pointer A

A => null()
end subroutine
> gfortran c_allocatables.c c_allocatables.f90
c_allocatables.f90:27:21:
10 |     subroutine null_alloc(A) bind(C)
|                         2
......
27 | subroutine null_alloc(A) bind(C)
|                     1
Warning: ALLOCATABLE mismatch in argument 'a' between (1) and (2)
> ./a.out 
T
F

最新更新