Fortran Coder

标题: 一个关于无类型指针的问题 [打印本页]

作者: lookbook    时间: 2019-7-3 00:39
标题: 一个关于无类型指针的问题
书上看到class(*)这么一个东西,
于是自己像下面这样使用


...

type(balabala) :: father

class(*),allocatable :: temp

allocate(temp,source=father)

...

但发觉死活不行,无论gfortran还是pgi

后来才领悟,原来class(*)类型的变量/指针只能在select type内使用。

突然觉得这东西局限很大啊,在此记录一笔,也供大家参考。



作者: liudy02    时间: 2019-7-3 07:31
我还没注意还有这个呢
你是原本以为可以有C里边void *那种神奇的功能?
作者: lookbook    时间: 2019-7-3 12:53
liudy02 发表于 2019-7-3 07:31
我还没注意还有这个呢
你是原本以为可以有C里边void *那种神奇的功能?

是的,不过在select type内部可以。
轻量级的代码或许能行
作者: liudy02    时间: 2019-7-3 13:40
lookbook 发表于 2019-7-3 12:53
是的,不过在select type内部可以。
轻量级的代码或许能行

不懂,我现在渐渐觉得fortran确实没啥不可替代性了
似乎一般的数学库也都有C语言版了
甚至连python里的numpy,scipy之类的库都做的很好了
fortran的oop做的那么烂,语言设计也确实不太好,感觉自己主动去用没啥必要了
也就是需要用别人的代码时需要搞清楚一些看不懂的问题就ok了
作者: lookbook    时间: 2019-7-3 16:22
liudy02 发表于 2019-7-3 13:40
不懂,我现在渐渐觉得fortran确实没啥不可替代性了
似乎一般的数学库也都有C语言版了
甚至连python里的nu ...

你会多少种语言了?
作者: liudy02    时间: 2019-7-3 17:02
lookbook 发表于 2019-7-3 16:22
你会多少种语言了?

老实说,一种也谈不上"会"啊
三四种都只是略知一点皮毛而已
但是fortran确实曾经用过很久,也花过不少功夫学习
确实发现曾经的优势都在慢慢消失,劣势却没有什么改善
作者: fcode    时间: 2019-7-3 18:10
class(*) 有挺多妙用的呀。
对于一些函数里不对输入数据进行操作,直接传递出去的,都可以用它。

我写过一个转换大小端的程序,用了 class(*) 之后,我就不需要为 real4 , real8 , real16 , integer2, integer4 , integer8 分别写一次了。

[Fortran] 纯文本查看 复制代码
program main
  implicit none
  Integer :: a
  Real :: b
  a = 3
  b = 1.0
  write(*,'("0x",z8.8)') a
  call CnvrtEndian( a , 4 )
  write(*,'("0x",z8.8)') a
  write(*,'("0x",z8.8)') b
  call CnvrtEndian( b , 4 )
  write(*,'("0x",z8.8)') b
contains

  Subroutine CnvrtEndian( byteIn , nByte )
    use , intrinsic :: ISO_C_Binding
    class(*) , target , Intent(INOUT) :: byteIn
    integer  , Intent(IN)             :: nByte
    character , pointer :: p(:)
    call c_f_pointer( c_loc(byteIn) , p , [nByte] )
    p = p(nByte:1:-1)
  End Subroutine CnvrtEndian
  
end program main

作者: liudy02    时间: 2019-7-3 19:18
fcode 发表于 2019-7-3 18:10
class(*) 有挺多妙用的呀。
对于一些函数里不对输入数据进行操作,直接传递出去的,都可以用它。

将一个数按位倒置,这个看起来不像是fortran这门语言设计的需求啊……
fortran设计的理念似乎一直是不要让用户去关心内部是怎么存储数据的
虽然后来引入了位操作函数,不也是不管实际存储情况,只是假设按固定位顺序存储设计的么?
作者: liudy02    时间: 2019-7-3 19:29
fcode 发表于 2019-7-3 18:10
class(*) 有挺多妙用的呀。
对于一些函数里不对输入数据进行操作,直接传递出去的,都可以用它。

从你这个例子里,学到一点
就是想利用这一点的话,相当于一定程度上可以使得子进程的哑元确实就是 void *的指针
只是实际要运用的话,还是受制于子进程内部能实现什么样的无关类型的通用代码
感觉这个如果和自定义算符以及通用函数名确实还是有很实际的运用的
一定程度上可以实现类似模板,或者多态的功能
作者: lookbook    时间: 2019-7-3 22:39
fcode 发表于 2019-7-3 18:10
class(*) 有挺多妙用的呀。
对于一些函数里不对输入数据进行操作,直接传递出去的,都可以用它。

谢谢绝地,
但这个代码在gfortran下测试并不成功,c_f_pointer不接受多态的指针,pgi是可以的,我猜ivf也是可以的吧。
还有请问为什么要用iso_c_binding?这段没有太明白。

后来我记起来了,fortran用父类指针也能实现一定的多态性质,只要顶层的接口设计好。
作者: liudy02    时间: 2019-7-3 22:53
本帖最后由 liudy02 于 2019-7-3 22:54 编辑
lookbook 发表于 2019-7-3 22:39
谢谢绝地,
但这个代码在gfortran下测试并不成功,c_f_pointer不接受多态的指针,pgi是可以的,我猜ivf也 ...

难道不是c_f_pointer这个子进程属于iso_c_binding这个内部模块?

用父类确实可以实现一定程度的多态,但我认为还是很不理想的
多态进程中涉及到的成员变量在某个子类里有变化可能就会要重载一堆方法
而且多数时候事情没那么复杂,可能就是想省码点包含基本运算的代码
结果却要层层设置类树,设置一堆运算符之类的,麻烦要死
所以我很欣赏有位大佬在这里推荐的在fortran里写模块的办法
只是那个办法也是建立在C预处理的基础上的
如果不是和C编译器继承在一起的fortran编译器,事情就麻烦的多了……
作者: randomzoom    时间: 2019-7-4 01:26
liudy02 发表于 2019-7-3 13:40
不懂,我现在渐渐觉得fortran确实没啥不可替代性了
似乎一般的数学库也都有C语言版了
甚至连python里的nu ...

其他语言,你会不知道怎么死的,特别是业务逻辑多的。
fortran的优点就是太傻了,不按照他的语法就是不过。
作者: fcode    时间: 2019-7-4 08:46
fortran语法设计得比较严谨,不确切的、可能因疏忽导致莫名其妙错误的,都被严格禁止了。
作者: lookbook    时间: 2019-7-4 11:05
liudy02 发表于 2019-7-3 22:53
难道不是c_f_pointer这个子进程属于iso_c_binding这个内部模块?

用父类确实可以实现一定程度的多态,但 ...

我的本意是为什么要用c_f_pointer这个函数
作者: fcode    时间: 2019-7-4 11:21
gfortran的 c_loc 不支持多态的话,可能就麻烦点,得用不规范的 loc

  Subroutine CnvrtEndian( byteIn , nByte )
    use , intrinsic :: ISO_C_Binding
    class(*) , target , Intent(INOUT) :: byteIn
    integer  , Intent(IN)             :: nByte
    character , pointer :: p(:)
    type(c_ptr) :: cp
    cp = transfer( loc(byteIn) , cp )
    call c_f_pointer( cp , p , [nByte] )
    p = p(nByte:1:-1)
  End Subroutine CnvrtEndian
作者: liudy02    时间: 2019-7-4 13:34
lookbook 发表于 2019-7-4 11:05
我的本意是为什么要用c_f_pointer这个函数

我没用过c和 fortran的交互
印象中,似乎fortran 的位操作都是假操作,还限定整数类型
所以我虽然没看懂版主是怎么做的,但是应该是把fortran的指针和c的指针相互转换
然后利用c来不分类型地对位进行倒置
作者: fcode    时间: 2019-7-4 17:39
差不多是这样。fortran语法太严苛,保证安全的同时,也有失灵活。
大多数时候,没必要这么做。
一部分过程,如果传入类型不重要,只是单纯的做别的事情,把传入参数直接传走,可以考虑用class(*)
作者: weixing1531    时间: 2019-7-6 21:41
本帖最后由 weixing1531 于 2019-7-6 22:08 编辑

楼主的设想还是可以实现的
只是class(*)多态指针p的断开引用必须在select type内部才行     
  但Fortran2018标准已经放松该限制  
  摘自电子书《Modern Fortran Explained  Incorporating Fortran 2018
  下载网址:http://www.doc88.com/p-0601727992809.html

[Fortran] 纯文本查看 复制代码
program main
    implicit none
    integer,target::a=3
    real,target::b=8.15
    class(*),pointer::p
   
    ALLOCATE(p,source=a) !f2018标准支持 p=a
    call write_p(p)
    p=>b
    call write_p(p)
    ALLOCATE(p,source=b) !f2018标准支持 p=b
    call write_p(p)
    p=>a
    call write_p(p)
contains
    subroutine write_p(p)
        class(*),pointer,intent(in)::p

        select type(p)
        type is(integer)
            write(*,"(I3)")p
        type is(real)
            write(*,"(F8.2)")p
        end select
    end subroutine write_p
end program







作者: lookbook    时间: 2019-7-7 15:01
weixing1531 发表于 2019-7-6 21:41
楼主的设想还是可以实现的
只是class(*)多态指针p的断开引用必须在select type内部才行     
  但Fortran20 ...

我没明白你的意思,看了下代码,这还是要在select type里才能进行操作(包括绑定的过程的调用)啊。




欢迎光临 Fortran Coder (http://bbs.fcode.cn/) Powered by Discuz! X3.2