我试图找到一种方法将带有可分配组件的派生类型对象传递给Fortran过程,而不需要知道类型定义的过程。要了解我为什么要这样做,背景信息可能会有用。
考虑一个包含稀疏矩阵 - 向量乘法的通用过程,就像Lanczos对角化例程一样。该过程本身不使用矩阵,只使用向量。该过程唯一需要对矩阵进行的操作是将它与向量一起传递给矩阵向量乘法例程。稀疏矩阵必须是具有可分配组件的派生类型变量。
我看到它的方式,程序不需要知道稀疏矩阵的数据类型。它只需要将它传递给矩阵向量乘法例程,然后将对其进行适当的解码。我试图做的是使用TRANSFER
内在函数将派生类型变量转换为可分配的字节数组,然后将其传回初始派生类型变量。遗憾的是,这不适用于具有可分配组件的派生类型变量,请参阅以下两个链接:Link 1,
Link 2
因此,如上所述,我的问题如下:是否有合理的方法*将带有可分配组件的派生类型对象传递给Fortran过程,而没有程序知道类型定义?
*注意:我知道我可以使用自定义内部格式化写入将派生类型变量存储到内部类型数组中,例如一个字符数组。这在我看来非常奇怪,但也许我错了?
EDIT ::正如Vladimir F所述,为可分配组件的派生类型调用TRANSFER
时的行为是非标准的。然而,我发现,令人惊讶的是,这适用于最新版本的PGI编译器。这是一个测试程序:
module Increments
TYPE :: structure
real s
integer q
real, allocatable :: flt1d(:)
END TYPE structure
contains
subroutine IncrementAndPrintReal(data)
character(len=1) :: data(:)
real :: r
r = transfer(data, r)
r = r + 1.0
print *,r
data = transfer(r, data)
end subroutine
subroutine IncrementAndPrintInteger(data)
character(len=1) :: data(:)
integer :: i
i = transfer(data, i)
i = i + 1
print *,i
data = transfer(i, data)
end subroutine
subroutine IncrementTenTimes(incrFunc, data)
character(len=1) :: data(:)
integer :: i
interface
subroutine incrFunc(data)
character(len=1) :: data(:)
end subroutine
end interface
do i = 1, 10
call incrFunc(data)
enddo
end subroutine
subroutine IncrementAndPrintStructure(data)
character(len=1) :: data(:)
type(structure) :: t0
t0 = transfer(data, t0)
print *, t0%flt1d
t0%flt1d = t0%flt1d(1) + 1
print*
data = transfer(t0, data)
end subroutine
end module
program main
use Increments
character(len=1), allocatable :: data(:)
integer :: lengthData
real :: r = 5.0
integer :: i = 10
type(structure) :: t
t%s = 1
t%q = 2
allocate(t%flt1d(11))
t%flt1d = 3
lengthData = size(transfer(r, data))
allocate(data(lengthData))
data = transfer(r, data)
call IncrementTenTimes(IncrementAndPrintReal, data)
deallocate(data)
lengthData = size(transfer(i, data))
allocate(data(lengthData))
data = transfer(i, data)
call IncrementTenTimes(IncrementAndPrintInteger, data)
deallocate(data)
lengthData = size(transfer(t, data))
allocate(data(lengthData))
data = transfer(t, data)
call IncrementTenTimes(IncrementAndPrintStructure, data)
deallocate(data)
end program
以下是不同编译器的结果:
ifort (v11.1 and v12.1.5):
==============
6.000000
7.000000
8.000000
9.000000
10.00000
11.00000
12.00000
13.00000
14.00000
15.00000
11
12
13
14
15
16
17
18
19
20
3.000000 3.000000 3.000000 3.000000 3.000000
3.000000 3.000000 3.000000 3.000000 3.000000
3.000000
0.0000000E+00 0.0000000E+00 4.000000 4.000000 4.000000
4.000000 4.000000 4.000000 4.000000 4.000000
4.000000
0.0000000E+00 0.0000000E+00 1.000000 1.000000 1.000000
1.000000 1.000000 1.000000 1.000000 1.000000
1.000000
0.0000000E+00 0.0000000E+00 1.000000 1.000000 1.000000
1.000000 1.000000 1.000000 1.000000 1.000000
1.000000
0.0000000E+00 0.0000000E+00 1.000000 1.000000 1.000000
1.000000 1.000000 1.000000 1.000000 1.000000
1.000000
0.0000000E+00 0.0000000E+00 1.000000 1.000000 1.000000
1.000000 1.000000 1.000000 1.000000 1.000000
1.000000
0.0000000E+00 0.0000000E+00 1.000000 1.000000 1.000000
1.000000 1.000000 1.000000 1.000000 1.000000
1.000000
0.0000000E+00 0.0000000E+00 1.000000 1.000000 1.000000
1.000000 1.000000 1.000000 1.000000 1.000000
1.000000
0.0000000E+00 0.0000000E+00 1.000000 1.000000 1.000000
1.000000 1.000000 1.000000 1.000000 1.000000
1.000000
0.0000000E+00 0.0000000E+00 1.000000 1.000000 1.000000
1.000000 1.000000 1.000000 1.000000 1.000000
1.000000
gfortran (gcc version 4.4.3):
=============================
6.0000000
7.0000000
8.0000000
9.0000000
10.000000
11.000000
12.000000
13.000000
14.000000
15.000000
11
12
13
14
15
16
17
18
19
20
3.0000000 3.0000000 3.0000000 3.0000000 3.0000000 3.0000000 3.0000000 3.0000000 3.0000000 3.0000000 3.0000000
1.82795013E-38 0.0000000 4.0000000 4.0000000 4.0000000 4.0000000 1.54142831E-44 1.12103877E-44 2.80259693E-45 4.0000000 4.0000000
*** glibc detected *** ./tr: double free or corruption (fasttop): 0x0000000000c70b20 ***
======= Backtrace: =========
/lib/libc.so.6(+0x77806)[0x7f9fb0e59806]
/lib/libc.so.6(cfree+0x73)[0x7f9fb0e600d3]
./tr[0x4010af]
./tr[0x401175]
./tr[0x40262e]
./tr[0x4026ea]
/lib/libc.so.6(__libc_start_main+0xfd)[0x7f9fb0e00c4d]
./tr[0x400a59]
======= Memory map: ========
00400000-00403000 r-xp 00000000 00:16 123 /home/stefanos/Documents/dig/progs/other/transfer/tr
00602000-00603000 r--p 00002000 00:16 123 /home/stefanos/Documents/dig/progs/other/transfer/tr
00603000-00604000 rw-p 00003000 00:16 123 /home/stefanos/Documents/dig/progs/other/transfer/tr
00c70000-00c91000 rw-p 00000000 00:00 0 [heap]
7f9fac000000-7f9fac021000 rw-p 00000000 00:00 0
7f9fac021000-7f9fb0000000 ---p 00000000 00:00 0
7f9fb0de2000-7f9fb0f5c000 r-xp 00000000 08:01 5512795 /lib/libc-2.11.1.so
7f9fb0f5c000-7f9fb115b000 ---p 0017a000 08:01 5512795 /lib/libc-2.11.1.so
7f9fb115b000-7f9fb115f000 r--p 00179000 08:01 5512795 /lib/libc-2.11.1.so
7f9fb115f000-7f9fb1160000 rw-p 0017d000 08:01 5512795 /lib/libc-2.11.1.so
7f9fb1160000-7f9fb1165000 rw-p 00000000 00:00 0
7f9fb1165000-7f9fb117b000 r-xp 00000000 08:01 5505258 /lib/libgcc_s.so.1
7f9fb117b000-7f9fb137a000 ---p 00016000 08:01 5505258 /lib/libgcc_s.so.1
7f9fb137a000-7f9fb137b000 r--p 00015000 08:01 5505258 /lib/libgcc_s.so.1
7f9fb137b000-7f9fb137c000 rw-p 00016000 08:01 5505258 /lib/libgcc_s.so.1
7f9fb137c000-7f9fb13fe000 r-xp 00000000 08:01 5505028 /lib/libm-2.11.1.so
7f9fb13fe000-7f9fb15fd000 ---p 00082000 08:01 5505028 /lib/libm-2.11.1.so
7f9fb15fd000-7f9fb15fe000 r--p 00081000 08:01 5505028 /lib/libm-2.11.1.so
7f9fb15fe000-7f9fb15ff000 rw-p 00082000 08:01 5505028 /lib/libm-2.11.1.so
7f9fb15ff000-7f9fb16ea000 r-xp 00000000 08:01 787983 /usr/lib/libgfortran.so.3.0.0
7f9fb16ea000-7f9fb18e9000 ---p 000eb000 08:01 787983 /usr/lib/libgfortran.so.3.0.0
7f9fb18e9000-7f9fb18ea000 r--p 000ea000 08:01 787983 /usr/lib/libgfortran.so.3.0.0
7f9fb18ea000-7f9fb18eb000 rw-p 000eb000 08:01 787983 /usr/lib/libgfortran.so.3.0.0
7f9fb18eb000-7f9fb18ec000 rw-p 00000000 00:00 0
7f9fb18ec000-7f9fb190c000 r-xp 00000000 08:01 5512780 /lib/ld-2.11.1.so
7f9fb1ad9000-7f9fb1add000 rw-p 00000000 00:00 0
7f9fb1b09000-7f9fb1b0b000 rw-p 00000000 00:00 0
7f9fb1b0b000-7f9fb1b0c000 r--p 0001f000 08:01 5512780 /lib/ld-2.11.1.so
7f9fb1b0c000-7f9fb1b0d000 rw-p 00020000 08:01 5512780 /lib/ld-2.11.1.so
7f9fb1b0d000-7f9fb1b0e000 rw-p 00000000 00:00 0
7fff5e340000-7fff5e356000 rw-p 00000000 00:00 0 [stack]
7fff5e396000-7fff5e397000 r-xp 00000000 00:00 0 [vdso]
ffffffffff600000-ffffffffff601000 r-xp 00000000 00:00 0 [vsyscall]
Aborted
pgfortran (v12.5):
==================
6.000000
7.000000
8.000000
9.000000
10.00000
11.00000
12.00000
13.00000
14.00000
15.00000
11
12
13
14
15
16
17
18
19
20
3.000000 3.000000 3.000000 3.000000
3.000000 3.000000 3.000000 3.000000
3.000000 3.000000 3.000000
4.000000 4.000000 4.000000 4.000000
4.000000 4.000000 4.000000 4.000000
4.000000 4.000000 4.000000
5.000000 5.000000 5.000000 5.000000
5.000000 5.000000 5.000000 5.000000
5.000000 5.000000 5.000000
6.000000 6.000000 6.000000 6.000000
6.000000 6.000000 6.000000 6.000000
6.000000 6.000000 6.000000
7.000000 7.000000 7.000000 7.000000
7.000000 7.000000 7.000000 7.000000
7.000000 7.000000 7.000000
8.000000 8.000000 8.000000 8.000000
8.000000 8.000000 8.000000 8.000000
8.000000 8.000000 8.000000
9.000000 9.000000 9.000000 9.000000
9.000000 9.000000 9.000000 9.000000
9.000000 9.000000 9.000000
10.00000 10.00000 10.00000 10.00000
10.00000 10.00000 10.00000 10.00000
10.00000 10.00000 10.00000
11.00000 11.00000 11.00000 11.00000
11.00000 11.00000 11.00000 11.00000
11.00000 11.00000 11.00000
12.00000 12.00000 12.00000 12.00000
12.00000 12.00000 12.00000 12.00000
12.00000 12.00000 12.00000
答案 0 :(得分:1)
您不能指望可分配组件的任何标准行为。在任何情况下,它们都存储在d中。类型结构,也不是简单的地址。如果您正在访问描述符或指针,那么我不清楚没有任何代码。无论如何,对于可靠的通用编程,您应该使用标准通用接口来处理多个过程,并且可能使用INCLUDE为它们使用公共主体。
答案 1 :(得分:1)
通过在PGI论坛中提出这个问题,我了解了可分配的无限多态对象CLASS(*), ALLOCATABLE
(感谢mkcolg)。这似乎是传递派生类型数据的更好方法,因为它允许在数据到达相关模块/过程时进行正确的类型检查。可以在PGInsider文章Object-Oriented Programming in Fortran 2003 Part 2: Data Polymorphism中找到示例。