Chinaunix首页 | 论坛 | 博客
  • 博客访问: 1736399
  • 博文数量: 438
  • 博客积分: 9799
  • 博客等级: 中将
  • 技术积分: 6092
  • 用 户 组: 普通用户
  • 注册时间: 2012-03-25 17:25
文章分类

全部博文(438)

文章存档

2019年(1)

2013年(8)

2012年(429)

分类: C/C++

2012-03-26 13:37:27

F90中,共有四种程序单元:主程序过程或辅程序块数据单元模块。下表是对它们的概括描述:

程序单元

定义

主程序

主程序是程序开始执行的标志,其第一条语句不能是SUBROUTINE,FUNCTION,MODULE和BLOCK DATA。主程序可以用PROGRAM语句作为第一条语句,但不是必需的

过程

子程序或函数

块数据单元

在命名的公共块中提供变量初始值的程序单元

模块

包含数据对象定义、类型定义、函数或子程序接口和其它程序可访问的函数或子程序


主程序是整个程序的入口,类似于C里的main函数。它的格式为:

[PROGRAM [程序名]]
    [说明部分]
    [可执行部分]
    [CONTAINS
        内部过程]
END [PROGRAM[程序名]]

可以看到主程序里可以有一个内部过程(在后面介绍)。

过程类似于C语言里的函数。它分为外部过程内部过程内在过程

外部过程独立于其它的程序单元,它的形式有两种:


外部函数FUNCTION语句
    [说明部分]
    [可执行部分]
    [CONTAINS
        内部过程]
END [FUNCTION函数名]


外部子程序SUBROUTINE语句
    [说明部分]
    [可执行部分]
    [CONTAINS
        内部过程]
END [SUBROUTINE子程序名]


内部过程是(通过contains语句)包含在宿主单元(外部过程、模块或主程序单元)内的过程,它的形式也有两种:

内部函数  :FUNCTION语句
    [说明部分]
    [可执行部分]
END [FUNTION函数名]


内部子程序SUBROUTINE语句
    [说明部分]
    [可执行部分]
END [SUBROUTINE子程序名]

可以看到内部过程不能再包含其它的内部过程。


内在过程就是Fortran的库函数,比如sin、abs等。Fortran90中定义了113个内在过程。

下面是子程序与过程(外部与内部)的例子:


  1.       program procedures
  2.       implicit none
  3.       integer:: x=5,y=6,res=0
  4.       integer:: add !声明函数(返回值)
  5.       character*8 get_something

  6.       call increase(x, y) !必须用call来调用一个
  7.       print *, x, y ! 6, 7
  8.       res = add(x,y)
  9.       print *, x, y, !7,8,15
  10.       print *, get_something() !hello
  11.       end

  12.       subroutine increase(x,y) !x,y为哑元,类似于C的参数,但是是引用
  13.       integer:: x,y; !声明实元,与哑元对应起来。类似于实参和形参的关系。
  14.       x = x + 1;
  15.       y = y + 1;
  16.       end

  17.       function add(x,y) result(s) !s为返回值
  18.       integer:: x,y,s;
  19.       x = x+1;
  20.       y = y+1;
  21.       s = x+y;
  22.       end

  23.       function get_something() !不声明result则函数名自身为返回值名
  24.       character*8 get_something;
  25.       call inner(get_something);
  26.       contains
  27.             subroutine inner(s) !内部过程
  28.             character*8 s
  29.             s = "hello"
  30.             end subroutine
  31.       end


External属性和哑过程用来调用外部文件里的过程,分别对应于C的extern关键字和外部函数声明。下面是一个例子:
caller.f:
  1.       program caller
  2.       integer,external:: add
  3.       print *, add(1,2)
  4.       end

callee.f:
  1.       function add(x,y) result(s)
  2.       integer,intent(in):: x,y !被声明为intent(in)的参数不能被修改
  3.       integer:: s
  4.       s = x + y
  5.       end


除了哑过程,还可以用interface来声明外部过程:
  1.       program caller
  2.       interface
  3.             function add(x,y)
  4.                   integer::x,y,add
  5.             end function
  6.       end interface
  7.       print *, add(1,2)
  8.       end


变元的save属性类似于c的static,而且在未声明的情况下变量 也都是save的。(而且我的gfortran(gcc4.5.2)根本不支持automatic属性,哪怕是用-fautomatic和 -frecursive的命令参数。这样所有的变量都只能是save的……fortran95本应该支持static关键字的,但我的gfortran也 不支持……)。

在调用子过程或函数时,可以使用关键字变元,使用关键字改变传入实参的顺序。比如:


  1.       program caller
  2.       interface
  3.             subroutine test_keyword_param(A,B,C,D)
  4.                   integer A,B,C,D
  5.             end
  6.       end interface

  7.       call test_keyword_param(62,C=83,D=7,B=2)
  8.       end

  9.       subroutine test_keyword_param(A, B, C, D)
  10.       integer A, B, C, D
  11.       print *, "A=", A;
  12.       print *, "B=", B;
  13.       print *, "C=", C;
  14.       print *, "D=", D;
  15.       end

在使用关键字变元时,必须在调用端定义一个接口。

另一个有趣的特性是可选变元,它用optional属性表示。代码如下:


  1.       subroutine test_optional_param(A, B, C, D)
  2.       integer A, B
  3.       integer, intent(in), optional :: C, D
  4.       print *, present(C)
  5.       !logical, intrinsic :: present
  6.       if (present(C)) then
  7.             print *, C, "as C is passed in!";
  8.       end if
  9.       if (present(D)) then
  10.             print *, D, "as D is passed in!";
  11.       end if
  12.       end

通过call test_optional_param(1,2)可以调用它。(我的gfortran编译出来的东西不管C,D有没有传入,present都返回true。真是2)

如果函数要支持递归的话,必须在函数前显式声明recursive属性,而且还必须有显式result声明。

通过接口可以把几个子过程合并成一个类属过程,类似于C里的模板的作用:


  1.       interface show
  2.             subroutine show_integer(x)
  3.                   integer x
  4.             end
  5.             subroutine show_real(x)
  6.                   real x
  7.             end
  8.       end interface

  9.       call show (55);
  10.       call show (32.13);
  11.       end

  12.       subroutine show_integer(x)
  13.             integer x
  14.             print *, "integer - ", x
  15.       end

  16.       subroutine show_real(x)
  17.             real x
  18.             print *, "real - ", x
  19.       end


块数据单元用来存放公共数据,它的形式为:

BLOCK DATA[块数据名]
    [说明部分]
END [BLOCK DATA[块数据名]]

推荐使用模块来存放公共数据,而非DATA。


Fortran中所有程序单元都是分别编译的,所以它们的作用域都是独立的。也就是说,一个程序单元内部的局部变量是不会被其它程序单元使用的。Fortran77使用了COMMONEQUIVALENCE共享数据

COMMON用于在不同的程序单元中共享数据的用法如下:


  1.       program common_test
  2.       common /group1/a,b,c
  3.       integer a,b,c
  4.       a = 5
  5.       b = 6
  6.       c = 7
  7.       call print_commons
  8.       end

  9.       subroutine print_commons
  10.       common /group1/x,y,z
  11.       integer x, y, z
  12.       print *, x, y, z !5,6,7
  13.       end


EQUIVALENCE用于在同一程序单元中共享数据:
  1.       program equivalence_test
  2.       integer a, b, c
  3.       character*8 e, f
  4.       equivalence (a, b, c), (e, f) !a,b,c共享数据;e,f共享数据
  5.       a = 5;
  6.       print *, a, b, c !5,5,5
  7.       b = 10;
  8.       print *, a, b, c !10,10,10

  9.       e = "ok"
  10.       print *, e, f !ok,ok
  11.       end


INCLUDE是一种共享代码(而非共享数据)的方法:
  1.       program interface_test
  2.             include 'mytype.f'
  3.             type(mytype) :: t1 = mytype(1,1.)
  4.       end

mytype.f的定义为:
  1.       type mytype
  2.             integer a
  3.             real b
  4.       end type


在Fortran90引入了模块MODULE的概念,它包含了COMMON、EQUIVALENCE和INCLUDE的功能。它是共享数据推荐使用的方式:
  1.       module mymodule
  2.             integer global
  3.             integer, private:: hidden

  4.             type mytype
  5.                   integer a
  6.                   real b
  7.             end type

  8.             type, private:: hiddentype
  9.                   integer x
  10.                   real y
  11.             end type

  12.             contains
  13.                   subroutine show
  14.                         print *, global, hidden
  15.                   end subroutine
  16.       end module

  17.       program interface_test
  18.             use mymodule

  19.             interface
  20.                   function add(x,y) result(z)
  21.                         use mymodule
  22.                         type(mytype), intent(in) :: x, y
  23.                         type(mytype) :: z
  24.                   end function add
  25.             end interface

  26.             type(mytype) :: t1 = mytype(1,1.)
  27.             type(mytype) :: t2 = mytype(2,2.)
  28.             type(mytype) :: t3
  29.             ! type(hiddentype) :: ht = hiddentype(5,0.5) !不能访问private type
  30.             global = 88
  31.             hidden = 99
  32.             call show !88, 0 private数据访问无效

  33.             t3 = add(t1, t2)
  34.             print *, t3%a, t3%b !3,3.0
  35.             call show !88,0 add函数里对global的赋值无效
  36.       end

  37.       function add(x,y) result(z)
  38.             use mymodule, only:mytype
  39.             type(mytype):: x,y,z
  40.             z%a = x%a + y%b
  41.             z%b = x%b + y%b
  42.             globle = 13 !允许,但无效
  43.       end

需要使用模块时使用use 模块名的方式。如果只需要使用模块的一部分,可以用“use 模块名,only: 需要使用的部分”的方式,如上面的add函数。

基于上例,这里展示一下Fortran中重载操作符的方法,.word.类型的也是一种操作符,类似于.and.和.or.:
  1.       module mymodule
  2.             type mytype
  3.                   integer a
  4.                   real b
  5.             end type

  6.             interface operator(+) !重载+
  7.                   module procedure add
  8.             end interface

  9.             interface operator(.add.) !重载.add.
  10.                   module procedure add
  11.             end interface

  12.             contains
  13.                   function add(x,y) result(z)
  14.                         type(mytype), intent(in):: x,y
  15.                         type(mytype) z
  16.                         z%a = x%a + y%b
  17.                         z%b = x%b + y%b
  18.                   end function
  19.       end module

  20.       program interface_test
  21.             use mymodule

  22.             type(mytype) :: t1 = mytype(1,1.)
  23.             type(mytype) :: t2 = mytype(2,2.)
  24.             type(mytype) :: t3

  25.             t3 = add(t1, t2)
  26.             t3 = t1 + t2
  27.             t3 = t1 .add. t2
  28.             print *, t3%a, t3%b !3,3.0
  29.       end

另外要重载赋值操作符的话需要用interface assignment(=)的方式。


阅读(3798) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~