1

我试图找到一种方法将具有可分配组件的派生类型对象传递给 Fortran 过程,而过程不知道类型定义。要了解我为什么要这样做,有关背景的一些信息可能会有用。

考虑一个包含稀疏矩阵向量乘法的通用过程,如 Lanczos 对角化例程。该过程本身不使用矩阵,仅使用向量。该过程唯一需要对矩阵做的就是将它与向量一起传递给矩阵向量乘法例程。稀疏矩阵必须是具有可分配组件的派生类型变量。

在我看来,程序不需要知道稀疏矩阵的数据类型。它只需要将它传递给矩阵向量乘法例程,然后它将对其进行适当的解码。我试图做的是使用TRANSFER内部函数将派生类型变量转换为可分配的字节数组,然后将其传输回初始派生类型变量。不幸的是,这不适用于具有可分配组件的派生类型变量,请参阅以下两个链接:链接 1链接 2

因此,如上所述,我的问题如下:是否有一种合理的方法*将具有可分配组件的派生类型对象传递给 Fortran 过程,而过程不知道类型定义?

*注意:我知道我可以使用自定义的内部格式化写入将派生类型变量存储到固有类型数组中,例如字符数组。这在我看来非常奇怪,但也许我错了?

编辑 :: 正如 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    
4

2 回答 2

1

您不能期望任何可分配组件的标准行为。在任何情况下,它们都不会存储在 d 中。类型结构,它们也不是简单的地址。如果您正在访问描述符或指针,我不清楚没有任何代码。无论如何,对于可靠的泛型编程,您可能应该对多个过程使用标准泛型接口,并且可能使用 INCLUDE 为它们使用公共主体。

于 2012-07-03T05:37:10.087 回答
1

通过在 PGI 论坛中提出这个问题,我了解了可分配的无限多态对象CLASS(*), ALLOCATABLE(感谢 mkcolg)。这似乎是传递派生类型数据的更好方法,因为它允许在数据到达相关模块/过程时进行适当的类型检查。示例可以在 PGInsider 文章Fortran 2003 第 2 部分中的面向对象编程:数据多态中找到。

于 2012-07-07T13:23:15.610 回答