使用可分配组件转换派生类型数据

时间:2012-07-02 17:28:04

标签: casting fortran transfer derived-types

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

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

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

2 个答案:

答案 0 :(得分:1)

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

答案 1 :(得分:1)

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