




已阅读5页,还剩6页未读, 继续免费阅读
版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领
文档简介
FORTRAN 静态库 动态库的生成 维护与调用静态库 动态库的生成 维护与调用 闫昊明闫昊明 2006 9 10 一 一 FORTRAN 静态库的生成与维护静态库的生成与维护 FORTRAN 静态库是经过编译的代码块 它与主程序相对独立 可以被主程序调用 是 FORTRAN 工程类型之一 静态库包含一系列子程序 但不包括主程序 静态库一般具有 LIB 扩展 名并包含目标代码 且静态库存放在它们特定的目录中 FORTRAN 静态库在组织大型程序和在不 同程序之间共享子程序等方面具有较大的优点 其重要性不言而喻 当将静态库与主程序联系起来 时 在主程序中调用静态库中的任何子程序将编译到相应的可执行程序 应用静态库的时候 只有 所需要的子程序才在编译过程中插入到可执行文件 EXE 这意味着这种可执行文件将比包含所 有的子程序所生成的可执行文件小 而且 不必担心哪些子程序是需要的 哪些是不需要的 编译 器将替你做出选择 同时 当更改静态库中的子程序时 相应的应用程序可以不做任何改变 而只 需要对其进行重新的编译链接 即可获得新的结果 这无疑也是方便的 目前 常用的 FORTRAN 静态库有很多种 WINDOWS 操作系统下的 Compaq Visual FORTRAN version 6 5 简称 CVF65 自带的数学统计库 IMSL 就是一个非常全面的静态库 可以 用来解决线性代数和统计学上的很多经典问题 此外 在 NCAR 互联网站有很多有用的 FORTRAN 子程序 网址 http www scd ucar edu softlib mathlib html 其中包括地球物理科学问题 离散和 快速 Fourier 变换 可分离的椭圆微分方程 插值 Legendre 多项式 普通数学问题 本征值问题 求解 线性方程求解 非线性方程求解 常微分方程求解 特殊函数 统计学等常用子程序集等 这些 FORTRAN 子程序可以解决很多基础性的问题 因此有很高的利用价值 在 WINDOWS 操作系统下 可以用两个命令分别生成静态库 一个是用 nmake 命令 它一 般用来编译原来应用在 UNIX 环境下的 FORTRAN 子程序集 在编译过程中要读取 makefile 文件中 的编译命令 类似于在 UNIX 下安装软件 另一个是用 lib 命令 它可以在 WINDOWS 环境下 编译任何需要集成为静态库的子程序集 编译静态库在 DOS 命令行环境下比较方便 以后的命令行都指在此环境下运行 在编译静态 库前 首先要安装 CVF65 其次要完成要编译的 FORTRAN 子程序 f90 对于 FORTRAN 子程序 最好用 FORTRAN90 的标准来完成 应该放弃 FORTRAN77 标准 FORTRAN90 是 FORTRAN 语 言从结构化走向面向对象化的重要一步 使 FORTRAN 语言更加接近 C 在 FORTRAN90 标 准中 对数组的操作既增强了功能又简化了使用 此外自由格式 MODULE 动态数组 指针等 的应用大大丰富了 FORTRAN 语言 使得编程更加轻松 目前 FORTRAN95 和 FORTRAN2000 标准也在应用 它们与 FORTRAN90 标准比较类似 主要的改进在并行运算方面 因此目前在单机 上应用的主要还是 FORTRAN90 在 DOS 命令行环境下 进入到 FORTRAN 子程序所在的子目录 然后按下面两个步骤生成 FORTRAN 静态库 1 键入 df f90 c 回车 可以看到 CVF65 编译器对所有的 FORTRAN 子程序 f90 进行编译 生成 obj 文件 注意 编译时 c 中的 c 必须小写 2 键入 lib obj out libname lib 回车 可以看到链接生成 libname lib 静态库 需要注意的是 每次加入新的子程序或对静态库中的子程序修改以后 都要按上述两个步骤重 新进行编译链接 生成静态库以后 可用 dumpbin linkermember libname lib 来查看静态库中可 用的子程序名称 也可执行 lib list libname lib 来查看静态库中的 obj 文件 当然 也可以在 CVF65 集成环境下 生成静态库 步骤如下 a 进入到 CVF65 集成环境下 依次打开菜单 File New FORTRAN Static Library 为新的静 态库命名 如 libname lib b 依次打开菜单 Project Add to Project Files 选择要编译的 f90 子程序到当前工作空间 c 依次打开菜单 Build Compile 和 Build Build 进行编译链接 生成 libname lib 静态库 在 当前目录中的 debug 子目录下 当要编译的静态库需要其它静态库支持时 在步骤 b 中将支持库 lib 也加入到当前工 作空间 即可顺利编译新的静态库 从上面的介绍可以看出 无论采用哪种方法 其基本步骤是一致的 即首先生成目标文件 obj 然后再将这些文件链接成一个静态库文件 lib 对于简单的静态库可以按第一种方法在 DOS 环境下生成 对于需要其它静态库支持的子程序集则可以首先加入库的路径 再在编译时链接这些 静态库 最后生成静态库文件 静态库生成以后还要经常进行更新和维护 以便更有效的利用这些资源 下面给出维护静态库 时常用的命令 将一个编译好的 obj 文件 如 ok obj 加入到现有静态库 如 libname lib 命令为 lib ok obj libname lib out libname lib 将两个或多个静态库合并成一个 all lib 命令为 lib 1 lib 2 lib 3 lib out all lib 或 lib lib out all lib 列出静态库中的成员 MEMBER 成员对大小写敏感 命令为 lib libname lib list outputfilename 可给出静态库中的成员 即 obj 从静态库中解出 extract 特定成员 命令为 lib libname lib extract member 从库中删除成员 命令为 lib libname lib remove member 二 二 FORTRANFORTRAN 静态库的调用静态库的调用 FORTRAN 静态库的调用主要有两种方式 第一种方式是在 DOS 环境下用命令行调用 其基 本命令为 df f lib 值得注意的是 在此种情况下 要设置合适的搜索路径 修改 CVF65 目录 下的子目录 bin 中的文件 dfvars bat 也可以直接将自己的静态库拷贝到 CVF65 默认库目录下 CVF65 根目录下的子目录 lib 中 第二种方式是在 CVF65 环境下调用 在此方式下有两种方法 方法一 首先对主程序进行编译 然后将静态库文件插入到当前工作空间 参考第一节步骤 b 再 进行链接 即可获得可执行文件 方法二 对主程序编译后 依次打开菜单 Project settings 在对 话框中选择 Link 选项卡 在 Object library models 项下加入静态库文件的名字 再进行链接 同样 可以获得可执行文件 上面所述的两种方法都比较麻烦 下面介绍在 FORTRAN90 语言环境中应用 MODULE 来解决 这一问题 首先建立一个 F90 的 module 程序 名字为 userlibmod f90 对所有静态库中的子程序在 此 module 程序中加入接口语句 其基本结构如下 为便于叙述 在每行都加了行号 源程序中应 无此行号 1 MODULE USERLIBMOD 2 DEC OBJCOMMENT LIB LIBNAME LIB 3 INTERFACE SUMAB 4 SUBROUTINE INT SUMAB A B C 5 INTEGER A B C 6 7 END SUBROUTINE INT SUMAB 8 SUBROUTINE REAL SUMAB A B C 9 REAL A B C 10 11 END SUBROUTINE REAL SUMAB 12 END INTERFACE SUMAB 13 INTERFACE 14 SUBROUTINE CALENDAR IY1 IM1 ID1 IY2 IM2 ID2 IUNITS NDAYS 15 INTEGER INTENT IN IY1 IM1 ID1 IY2 IM2 ID2 IUNITS 16 INTEGER INTENT OUT NDAYS 17 18 END SUBROUTINE CALENDAR 19 END INTERFACE 20 END MODULE 从这个 module 的结构可以看出 第 1 行要给出 module 的名字 最好与文件名相同 第 2 行告 诉编译器要链接的静态库的名字 这里虽然看似注释语句 其实不是 此行可以在编译的过程中与 编译器进行通讯 不能省略 不然可能造成编译错误 3 到 12 行是一个有名接口语句 这里边有 两个子程序 对整数和实数分别求和 我们可以用两个子程序名来分别调用对应的两个数求和 也可以用接口名来直接调用这两个子程序 当用接口名来调用时 如果输入的参数是整数 相当于 调用 int sumab a b c 如果输入的参数是实数 相当于调用 real sumab a b c 所以在 F90 语言中 可以简化调用函数的个数 13 到 19 行定义了另外一个无名接口 接口中也可以加入多个类似 14 行到 18 行的子程序或函数 这些子程序或函数必须已经编译到静态库 LIBNAME LIB 中 20 行 是 module 的结束语句 将编辑好的 module 程序存盘 在命令行下执行 df userlibmod f90 c 即可生成 MOD 文件 userlibmod mod 将此 MOD 文件放入合适的地方 如 d myforlib include 再将生成的静态 库文件放入相应的路径 如 d myforlib lib 则一个自己的静态库就建成了 为了应用此静态库 首先要对 CVF65 设置合适的搜索路径 打开 CVF65 集成环境 依次打开 菜单 tools options directories 在 show directories for 下拉菜单中依次点击 include files 和 library files 然后再下面的 directories 中在空白处依次将 d myforlib include 和 d myforlib lib 加入 点击 ok 按钮 即完成了对搜索路径的设置 现在 就可以方便的调用 静态库中的子程序或函数了 只需要在你自己的主程序中第一行加入如下语句 use userlibmod 即 可 如果第一行是 program yourprogramname 则将其加入到此行的下一行 三 静态库的其它说明三 静态库的其它说明 如果你应用的 FORTRAN 编译器是 INTEL VISUAL FORTRAN 9 0 IVF 以上的版本 可以 按照和上面的过程类似的方法来生成静态库 唯一的区别是编译命令不同 IVF 用 ifort 命令进行编 译 而 lib 命令是一致的 此外 对于 IVF 路径的设置是 ifortvars bat 文件 其它的内容都是类似的 需要注意的是 由于采用了不同的编译器 CVF 和 IVF 编译的静态库一般不能共享 需要重新编 译 作者已经发布了自己编译的 FORTRAN 静态库软件 WHIGG F90 LIB WFL 可以从 访问 有关静态库的问题可以发送 email wfllib 四 动态库与静态库的联系与区别四 动态库与静态库的联系与区别 上面我们详细介绍了静态库的生成维护与使用 我们在此做一个小的总结 静态库在使用的时 候 首先把需要使用的函数编译成机器代码 保存在 lib 文件中 然后在主程序中调用这些静态库 中的函数时 编译器会到指定的 lib 文件中找出所需要的函数代码 或称之为机器码 并把这些 代码复制一份 从而一起放到可执行文件 exe 中 这样就可以使 exe 文件脱离 lib 文件 在操作系 统中单独运行 也就是说 这样编译得到的 exe 文件具有独立性 当然 这是跟动态库相比而得出 的结论 再来说说动态库的使用 大家经常在计算机系统里面看到 dll 为后缀的文件 觉得很神奇 它 就是系统中必不可少的动态链接库文件 其实 动态库跟静态库类似 也是计算机中使用库函数的 另一种技术 它同样是把多个功能不同的函数使用编译器编译成机器码 然后存储在 dll 文件中 与静态库不同的是 如果主程序调用的是动态库函数 那么编译器在编译的时候将不会把动态库中 的机器码复制到可执行文件 exe 中去 编译器只会在 exe 文件中说明要调用的函数放在哪个动态库 中 其位置在那里 当 exe 文件执行到这些在动态库中的函数的时候 操作系统就会把 dll 文件中 的函数拿出来交给 exe 文件去执行使用 同 windows 系统类似 在 unix linux 系统中也可以编译动 态链接库 只不过他们的文件名是以 a 结尾而已 其编译器也略有不同而已 DLL 文件有三个好处 第一 可以让 Fortran 语言很好的与其它语言 如 c VC VB Delphi 等进行混合编程 这样可以利用各自的优点 如 fortran 强于计算 而 c VB 等做界面比较方便 从而给出界面更友好的计算软件 达到人机更好的对话的效果 第 二 可以有效的减少 exe 文件的大小 我们可以把很多程序共同使用的函数放在特定的 DLL 文件 中 让执行文件变小 以减少对硬盘资源的消耗 如果使用静态库 每个 exe 文件所使用的函数都 会复制在对应的 exe 文件中 执行文件将因此变大 这样的选择并不是最佳的 第三 DLL 文件容 易更新 因为 DLL 文件和 exe 文件是分离的 不在同一个文件中 因此只要更新必要的 DLL 文件 而不需要重新编译 exe 可执行文件 这样就可以得到最新版本的链接库 如果使用静态库 则必须 重新编译 exe 可执行文件 才能链接新的更新库 五 用五 用 FORTRANFORTRAN 语言编译动态链接库语言编译动态链接库 使用 Fortran 语言来编译静态库 用 CVF 的命令行方式最直观 命令格式为 df f90 dll dllfilename 由于是编译动态库 Fortran 源程序的内容要添加一部分内容 下面我们给一个具 体的例子来说明 1 Subroutine add a b c 2 DEC ATTRIBUTES DLLEXPORT ADD 3 DEC ATTRIBUTES ALIAS ADD ADD 4 Implicit none 5 real intent in a b 6 real intent out c 7 c a b 8 contains 9 subroutine prt 10 print a b c 11 end subroutine prt 12 end subroutine add 我们首先把上面的代码储存为 add f90 文件 在这个文件中 我们定义了一个 subroutine 名字 为 add 其目的是把 a 和 b 两个参数求和 然后返回 c a b 的值 注意到 这个 subroutine 与一 般的 subroutine 的不同点在第 2 和第 3 行 其中 第 2 行是必须的 而第 3 行可以省略 第 2 行的 作用是定义输出的 dll 函数名称 这样 dll 文件就可以告诉操作系统 在此 dll 里面 哪些函数是可 以被调用的 注意 第 2 行这个命令也是隐含在注释中的 但编译器遇到 DEC 为开始的注释行会 知道这是传递给 FORTRAN 编译器的功能选项 知道这是在 dll 中输出一个函数名 在 dll 中 只 有这种有明确输出接口的函数才能对外公开使用 没有使用这种接口 或称之为命令 DEC 对 于不同的编译器 其 dll 接口的定义可能是不同的 比如以前也应用过 MS 等 这个需要查找编译 器的帮助文件 以便正确的理解何接口才是编译器认识的 的函数只对 dll 内部函数有效 对外是 不可见的 譬如 上例中的 9 到 11 行定义了一个内部函数 prt 用来打印 a b c 三个值到屏幕上 这个函数对 dll 以外的函数是不可见的 也不能调用 同样 prt 函数也不能用 DEC ATTRIBUTES DLLEXPORT PRT 来声明 这会导致编译错误 现在在 CVF 的 command 命令行方式下 用 df add f90 dll TEST DLL 就可以生成一个 TEST DLL 动态链接库 在生成动态链接库的同时 还将生 成以下文件 TEST LIB TEST EXP 其中 TEST LIB 文件是在编译调用 TEST DLL 动态链接库的主 程序时必须提供的文件 TEST LIB 文件是 TEST DLL 的辅助文件 它里面没有函数 add 的机器码 但是说明了 add 函数在哪个 dll 里 TEST EXP 文件是由 LIB 工具从 DEF 文件生成的输出文件 其 中包含了函数和数据项目的输出信息 LINK 工具将使用 EXP 文件来创建动态链接库 只有在编译 DLL 时才会生成 记录了 DLL 文件中的一些信息 TEST EXP 文件对用户来讲 没有更多的实际 作用 六 动态链接库的调用六 动态链接库的调用 下面我们编辑一个主程序 用来调用 TEST DLL 这个动态链接库 程序名称为 test f90 内容 如下 1 module testdll 2 DEC OBJCOMMENT LIB TEST LIB 3 interface 4 subroutine add a b c 5 DEC ATTRIBUTES DLLIMPORT ADD 6 DEC ATTRIBUTES ALIAS ADD ADD 7 real intent in a b 8 real intent out c 9 end subroutine add 10 end interface 11 end module testdll 12 program test 13 use testdll 14 real a b c 15 a 1 0 b 2 5 16 call add a b c 17 end 在命令行下或在 IDE 集成环境下对 test f90 进行编译 命令行下的命令为 df test f90 注意 此时 TEST LIB 文件要与 TEST F90 在同一目录下 或是 TEST LIB 文件在 lib 的搜索路径中 这样 就可以生成 TEST EXE 可执行文件 执行 TEST EXE 可执行文件可能会出现找不到 TEST DLL 错 误这样一个对话框 这是因为 TEST DLL 不在系统的搜索路径或不和 TEST EXE 在同一目录 将 TEST DLL 放到 TEST EXE 的目录下或放到 C WINDOWS SYSTEM32 目录下 就可以顺利运行 TEST EXE 注意 1 到 11 行我们定义了一个 module 这样使得主程序在调用 dll 时 有明显的接 口 在接口中 3 到 10 行 我们给出了 add 函数的接口 其中 5 和 6 行是告诉主程序要引入 add 这 一 dll 中的函数 第 2 行定义了需要链接的对应于 TEST DLL 的静态库文件 TEST LIB 这也是在编 译可执行文件时所不能或缺的 以上 我们比较详细的讲了如何生成动态链接库 如何调用动态链接库 如果是大型的动态链 接库 将会设计到非常多的 FUNCTION 和 SUBROUTINE 此外在某一个 FUNCTION 或 SUBROUTINE 中还会调用其它的 FUNCTION 和 SUBROUTINE 这时的 FUNCTION 和 SUBROUTINE 就要稍微复杂一些 再举个例子 例如 SUBROUTINE 的内容如下 1 SUBROUTINE ADD1 A B C 2 DEC ATTRIBUTES DLLEXPORT ADD1 3 DEC ATTRIBUTES ALIAS ADD1 ADD1 4 DEC ATTRIBUTES DLLIMPORT DIV 5 DEC ATTRIBUTES ALIAS DIV DIV 6 REAL INTENT IN A B 7 REAL INTENT OUT C 8 INTERFACE 9 FUNCTION PLUS AA BB 10 DEC ATTRIBUTES DLLIMPORT PLUS 11 DEC ATTRIBUTES ALIAS PLUS PLUS 12 REAL INTENT IN AA BB 13 REAL PLUS 14 END FUNCTION PLUS 15 END INTERFACE 16 REAL AA BB D E 17 AA 1 0 BB 6 0 18 D PLUS AA BB 19 CALL DIV D E 20 A E 21 C A B 22 END SUBROUTINE ADD1 在这个例子里面 在 ADD1 这个 SUBROUTINE 里面调用了一个名为 DIV 的 SUBROUTINE 还 调用了一个名为 PLUS 的函数 注意 2 到 5 行和 8 到 14 行的写法 对于 SUBROUTINE 来讲 一 般直接用 4 到 5 行这样引用就可以了 对于 FUNCTION 来讲 最好是写在一个接口里面 如 8 到 14 行 当然也可以写成 4 到 5 行的形式 如果 FUNCTION 和 SUBROUTINE 里面有 optional 变量 的话 则最后用 INTERFACE 写成一个完整的接口里面 这样就不会出现问题 当然 你也可以将 所有的接口都定义在一个 module 中 此时要用 DLLIMPORT 属性 然后用 use 调用也可以 需要 注意的是 对于 CVF 自带的内部函数 不需要加任何东西 直接调用就可以了 对于 IMSL 中的 库函数 同样只要用 use numerical libraries 来引用就可以了 也不用加 DEC ATTRIBUTES 等这 些属性 至于其它语言如何调用 FORTRAN 编译的动态链接库 请参考相关的文献 在此不再详述 七 动态链接库的发布七 动态链接库的发布 编译好动态链接库以后 就可以把他与可执行文件一起发布了 但很多时候 在自己的计算机 上运行的很好的程序到别人的计算机上就运行不了了 出现缺某某 dll 的错误对话框 这是因为 你所编译的 dll 是与系统内部的一些 dll 相关的 要运行你自己的 dll 还需要其它的 dll 来支持 如 果没有这些 dll 支持 就会出现上述错误 解决的办法有一个 把这些关联的 dll 也一起发给用户 那么 怎么才能知道还需要那些关联的 dll 呢 其实 CVF 提供了一个工具 叫做 dependency walker 在开始菜单中的 CVF 的程序菜单中可以找到 用这个小工具打开你的 dll 文件 就会看到 与之相关联的 dll 了 当然 并不是所有的 dll 都需要与可执行文件一起复制发布 譬如说 kernel32 dll 就是系统自带的 不需要一同复制 你可以在 dependency walker 中右键需要查看的 dll 文件 在属性的版本等信息中可以发现此 dll 文件是否是系统文件 这样就可以很好的区分哪些是 必须要复制的文件 哪些是不需要的 当然也可以看到这些 dll 文件所在的位置 当然这个工具其 实也就是 C 语言中的 depends exe 这个小工具 八 静态库和动态库的条件编译八 静态库和动态库的条件编译 上面讲到了分别对静态库和动态库进行编译 但我们面对的事实是 我们只想管理一套源程序 而不是分别为静态库和动态库各自建立一套类似的源程序 只有一些 DEC ATTRIBUTES 的区别 这样会增加管理的难度和出错的几率 解决这一问题的一个方法就是利用条件编译 这是 利用了 General Compiler Directives 的功能 对源程序进行条件编译 条件编译的源程序可按下面的 方法来写 DEC IF expr or DEC IF DEFINED name block DEC ELSEIF expr Block DEC ELSE Block DEC ENDIF Expr 是一个逻辑变量 具有 TRUE 或是 FALSE 值 name 是定义的符号名称 block 是在各种不 同条件成立下的执行块体 这里 我们可以采用事先定义符合名称来实现静态库和动态库的源程序合二为一 举个例子 1 SUBROUTINE AAA A1 A2 2 DEC IF DEFINED DLLFLAG 3 DEC ATTRIBUTES DLLEXPORT AAA 4 DEC ATTRIBUTES ALIAS AM2EAM AAA 5 DEC ELSE 6 HERE IS THE CODE FOR STATIC LIB 7 DEC ENDIF 8 9 END SUBROUTINE AAA 在这个例子中 我们首先定义了一个子程序 AAA 然后用条件编译的方式来区分动态库和静态库 如果在编译时定义了符合 DLL FLAG 那么将执行 3 4 行语句 如果没有定义 DLL FLAG 那么 将执行 6 行的内容 然后 无论是否定义了 DLL FLAG 都将执行 8 行的内容 如果将上述子程 序 名称为 AAA F90 编译成静态库 可以用如下命令 df aaa f90 c lib aaa obj out aaa lib 如果要编译成动态库 可以采用如下的命令行命令 df aaa f90 dll aaa dll define DLL FLAG 这样我们就解决了同时用一个源程序来编译成不同形式的目标代码 大大的减少了代码的重复性管 理 提高了效率 九九 不同语言调用动态库应注意的问题不同语言调用动态库应注意的问题 FORTRAN 语言生成的 DLL 可以被其它语言所调用 但在正确调用之前 首先要保证在不同 语言中的参数传递的正确性 这里主要介绍 C 或 C 语言调用 FORTRAN 的 DLL 应该注意的问 题 字符变量字符变量 在 C 语言中 一个字符占一个字节 且字符串的最后一个字符是 NULL 或者是 0 Fortran 语 言中 字符串没有象 C 语言这样的最后一个 NULL 或 0 字符 字符串一般是传址方式 而不是传 值方式进行引用的 因此可能引起错误 传址方式意味着计算机把字符串的首位字符的地址传递到 内存中 而不是传递整个字符串的值 当 Fortran 过程运行完成以后 它仅仅把字符的首位地址传 递给用 C 语言写的主程序 这样 C 语言的主程序只知道字符串的首地址 却不知道哪里是字符串 的结束 因为没有 NULL 或是 0 字符在这样一个字符串的结尾 尽管传递字符有许多好处 例如 传递错误信息 避免这个问题的最好办法是不传递字符串 参数 其次 可以把字符串的长度作为一个参数来传递 这样也可以避免上面的问题 此外 还可 以在 FORTRAN 的 DLL 中 固定字符串的长度 使他们同为一个确定的长度 例如 255 个字符 这样可以方便 C 语言的调用 整数和浮点数变量整数和浮点数变量 我们知道 不同的 FORTRAN 编译器和不同的操作系统中 整数和浮点数的定义是不尽相同的 例如 在 windows 系统中 一个整数可以定义为 1byte 8bits 2byte 16bits 4byte 32bits 8byte 64bits 一个浮点数可以是 4byte 32bits 或是 8byte 64bits 还可能是 16byte 128bits 或是 10byte 等 为了防治不同语言中整数和浮点数的不同 最好应用 4byte 的整 数和 8byte 的浮点数 数组参数数组参数 在主程序和 DLL 之间传递数组 也可能出现问题 数组与字符参数类似 其缺省的传递方式 是传址方式而不是传值方式 而且 在很多情况下 最好把数组的维数和大小用整数传递 调用约定调用约定 CallingCalling ConventionsConventions 当生成或是调用 DLL 的时候 必需正确指出 DLL 的调用约定 如果不能正确调用 那么 最 好的情况是 DLL 不能正确工作 最糟糕的情况可能引起计算机崩溃 也许有人会问 为什么调用 或生成 DLL 没有一个统一的标准呢 调用约定是用于链接 link 静态目标码 static objects 的 因此不同的编译器会定义不同的调用规则用来区分和调用静态目标码 从而链接成可执行文件 即 使不同的编译器具有不同的调用约定 但对其自己来说不存在任何问题 每个编译器都有自己的一 套规则 不需要进行统一 但如果生成 DLL 然后用不同的编译器进行调用的话 调用约定确实 成了一个问题 而且是一个非常关键的问题 在 Windows 系统 各个不同编译器之间的调用约定 只有微小的差别 但即使再小的差别也可能导致不能正确调用 DLL 因此必需重视调用约定的统一 传址还是传值 传址还是传值 不论是传址还是传值 都可以应用在 DLL 中 但需要注意的是 在生成和调用 DLL 过程中 使用统一的调用原则 DLL 是传址的就传址调用 是传值的就传值调用 传址或是传值可以在 ATTRIBUTE 中定义 分别是 REFERENCE 和 VALUE 两个关键字 例如 DEC ATTRIBUTE VALUE A1 DEC ATTRIBUTE REFERENCE A2 调用过程名称 调用过程名称 SymbolicSymbolic namesnames 调用过程名称是用来区分 DLL 输出表中的过程的唯一标志 一般情况下 调用过程名称与 FORTRAN 的子程序或函数同名 但有些情况下 在特定的调用约定下 有的调用过程名称前面有 一个下划线 且调用过程名称的大小写也可能有区别 因此在调用 DLL 时 必需注意这些问 题 当然 我们可以定义 ATTRIBUTE 中的特定关键字来强制输出调用过程名称 这样可以减少调 用过程中的麻烦 在 DLL 生成后 可以用 Dumpbin exports dll 来查看有哪些调用过程名称是可 用的 在调用 DLL 过程中 调用过程名称必需与 DLL 输出表中的名称一致 在编译 FORTRAN 的 DLL 时 也可以使用命令参数来强制调用过程名称 下面是一个例子 ifort names lowercase as is iface cref dll assume underscore align sequence 参考文献 1 Compaq Visual Fortran Ver 6 6C online help 2 彭国伦 FORTRAN95 程序设计 中国电力出版社 北京 2002 3 Lemmon D R J L Schafer Developing statistical software in Fortran 95 Springer 2005 windowXP 下 IVF CVF 子程序调用格式说明及混合语言编程 最近在编译 ScaLapck 需要的 BLACS 时遇到了 Fortran 语言与 C 语言之间的相互调用问题 经过几天的研究 终于 有点收获了 一 IVF 和 CVF 中程序调用格式 1 IVF 对子程序名和参数的调用规则 Intel Visual Fortran IVF 中调用子程序时 编译器默认 即使用参数 iface default 是按参数传址方式 子程序中对参 数进行修改 返回到主程序后参数也是被修改了 程序名大写进行调用的 若参数中包含有字符参数时 是按隐含 字符长度的方式进行传递的 即在字符参数后紧接着有一个隐含的整型数用来指用字符长度的 在程序编译时可以通过 iface 参数来改变子程序的调用规则 以下以一个例子来进行说明 Subroutine MySub1 int1 real1 char1 int2 real2 char2 Integer 4 int1 int2 Real 8 real1 real2 Character char1 3 char2 End Subroutine MySub1 A 当默认编译参数或用 iface default 时 调用参数按地址进行传递 在编译时会将上面这个子程序名编译为 MYSUB1 大写 参数列表为 int1 real1 char1 int3 int2 real2 char2 int4 若主调用程序也是用 Fortran 编写的话 参数列表中的方括号内的参数是不需要显式的指定的 因它主程序和子程序都符合 IVF 默认的调用规则 但若主调 用程序为其它语言编写的 比如 VB 侧在调用时需要给出参数列表中方括号内的整形数以说明其前面的字符长度 B 当编译参数用 iface cref 时 调用参数按地址进行传递 编译后的子程序名为 mysub1 小写 参数列表同 A C 当编译参数用 iface stdref 时 调用参数按地址进行传递 编译后的子程序名为 mysub1 n 子程序名小写 n 为 参数列表中所有参数所占字节数 参数列表同 A D 当编译参数用 iface C 时 调用参数按值进行传递 编译后的子程序名为 mysub1 小写 参数列表同 A E 当编译参数用 iface STDCALL 时 调用参数按值进行传递 编译后的子程序名为 mysub1 n 子程序名小写 n 为参数列表中所有参数所占字节数 参数列表同 A F 当编译参数用 iface CVF 时 调用参数按地址进行传递 编译后的子程序名为 MYSUB1 n 子程序名大写 n 为 参数列表中所有参数所占字节数 参数列表同 A 与情况下 CVF 中默认的子程序调用相同 另外 在以上几种情况下 若指定了编译参数 iface nomixed str len arg 则参数列表为 int1 real1 char1 int2 real2 char2 int3 int4 即字符长度参数位移参数列表最后 若主调用程序也是用 Fortran
温馨提示
- 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
- 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
- 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
- 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
- 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
- 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
- 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。
最新文档
- 市场开发合作协议及附件
- 专业技能培训合格证明书(8篇)
- 农业养殖技术改良与应用协议
- 行政管理市场营销试题及答案总结
- 企业战略与资源配置的动态关系试题及答案
- 2025年农村住宅建设规范:自建住宅买卖合同
- 行政管理本科课程试题及答案总结
- 行政管理学考试常见题型试题及答案
- 2025年行政管理考核模式试题及答案
- 建筑工程考试前沿试题及答案分析
- 政协理论知识讲座课件
- 2025年中考英语第一次模拟考试(苏州卷)(原卷版)
- 福州一号线盾构法地铁工程整体施工组织设计
- 购买学位合同协议
- 公务员考试-经济基础知识模拟题-计量经济学-协整与误差修正模型
- 资源与运营管理-第一次形考任务-国开-参考资料
- 五年级下册数学教案 - 8.1《复式条形统计图》 北师大版
- 2025年二建《建筑工程管理与实务》考前必刷必练题库500题(含真题、重点题)
- 2025云南师范大学辅导员考试题库
- 学生健康档案管理制度
- Unit 7 A Day to Remember Section A (课件)-2024-2025学年英语人教版7年级下册
评论
0/150
提交评论