Fortran Coder

查看: 14856|回复: 14
打印 上一主题 下一主题

[混编] FORTRAN与C#混合编程的调用约定

[复制链接]

58

帖子

9

主题

0

精华

熟手

F 币
256 元
贡献
163 点
跳转到指定楼层
楼主
发表于 2016-10-29 14:35:02 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
大侠好!
我这帖子内容比较多,还请耐心,问题也比较多,有些涉及到两种语言。我写的这么详细,也是真心希望能为有类似需求的同仁提供参考。
我想通过Fortran 控制台程序编写相应算法的动态链接库,然后利用C#编写的界面程序调用在Fortran 中生成的DLL 文件。
用FORTRAN与C#混合编程的调用约定中,主要有四点,有些不明白的地方(详见红色文字部分),还请指教:
一:堆栈管理约定
在Fortran 语言中是通过相应的编译器的通用指令“! DEC $ ”后添加可选项“C”或“StdCALL”这两个参数来实现的:
! DEC $ ATTRIBUTES StdCALL: : Filename
! DEC $ ATTRIBUTES C: : Filename
第一条语句中说明的是StdCALL 模式,这种模式是由被调用方清除堆栈( 其中Filename 为函数名或变量名) ,第二条语句说明的是C 模式,这种模式是由主
调函数清除堆栈( 对于传递数组和字符串参数这两种情况,该方法不可以使用) 。以上是在Fortran 中做相应的改动,在C#语言中也可以做不同的改动,即设置DllImport 属性,通过改
变CallingConversion 字段的值,来规定堆栈的清理方式( Cedel 代表由调用方清理堆栈,StdCALL 代表由被调用方清理堆栈) :
[DllImport( “Filename. dll”,CallingConvention =CallingConvention Cdel) ]
[DllImport( “Filename. dll”,CallingConvention =CallingConvention StdCall) ]
我想了解的是:
1、如果我在FORTRAN代码中输入
! DEC $ ATTRIBUTES StdCALL: : Filename
那在C#代码中需要输入CallingConvention Cdel还是CallingConvention StdCall?
2、关于FORTRAN调用约定的详细说明,在哪里能找到呢(我在帮助文件中找过,感觉介绍得不是特别详细)?


二:命名约定
C#语言是区分大小写的,而Fortran 是不区分的。从DLL 导出的Fortran 函数名会自动转换为大写,这是由编译器自动完成的。所以,在C#中就无法找到Fortran 中声明相同的函数名了。为了协调
标识符的不一致必须进行命名约定的协调。在Fortran 语言中做相应的改动是使用ALIAS( 别名) 属性,即指定导出的函数名。例如下面的Fortran函数:
subroutine Filename( A)
integer A
相应的C#声明为:
[DllImport( “Math. dll”) ]
Public extern static void FILENAME( int a) ;
使用ALIAS 修改后的定义如下:
subroutine Filename( A)
! DEC $ ATTRIBUTESALIAS: ‘_ Filename’: :Filename
integer A
对应的C#声明为:
[DllImport( “Math. dll”) ]
Public extern static void Filename( int a) ;
我想了解的是:
1、我只需要在FORTRAN中使用ALIAS 修改变量A的定义,而在C#不需要做任何修改就可以吗?
2、有哪些变量需要修改其定义,与动态链接库有关的变量是否都需要修改(我在FORTRAN中用到了IMSL动态链接库和其他动态链接库)?

以上是在Fortran 语言中的解决方案,也可在C#语言中做相应的改动,通过使用DllImport 的EntryPoint属性来指定导出的Fortran 函数名。
subroutine Filename( A)
integer A
对应的C#声明为:
[ DllImport ( “ Math. dll ”, EntryPoint =“FILENAME”) ]
Public extern static void Filename( int a) ;
我想了解的是如果我采用这种解决方案:
1、我只需要在C#中使用ALIAS 修改变量A的定义,而在FORTRAN不需要做任何修改就可以吗?
2、两种解决方案中,哪种更加合适,比如运行更加稳定,不容易出错。

三:参数传递约定
在Fortran 中默认的是所有的参数使用引用传递的方式,而对于C#语言则存在值传递和引用传递两种方式。C#中所有的数值类型的参数传递方式都是值
传递,而表示字符串的类型的参数传递方式都是引用传递。解决这个问题可以通过分别在Fortran 和C#方面做相应的设置。在Fortran 语言中,可以通过VALUE
属性指定参数传递使用值传递的方式。
subroutine Filename( A)
integer A [VALUE]
对应的C#声明为:
[DllImport( “Math. dll”,CallingConvention = CallingConvention.StdCall) ]
Public extern static void Filename( int a) ;

我想了解的是:
1、如果我采用这种解决方案,变量A的已经是使用值传递了,那为什么还要在C#中再次声明呢?
2、有哪些变量需要设置值传递,与动态链接库有关的变量是否都需要修改(我在FORTRAN中用到了IMSL动态链接库和其他动态链接库)?


在C#语言做改动的话可以使用C#的ref 关键字,从而保证函数传递给Fortran 语言的参数是该参数的地址。
subroutine Filename( A)
integer A [VALUE]
对应的C#声明为:
[DllImport( “Math. dll”,CallingConvention = CallingConvention.StdCall) ]
Public extern static void Filename( ref int a) ;

我想了解的是:
1、如果我采用这种解决方案,已经使用C#的ref 关键字,那为什么还要在FORTRAN中声明为[VALUE]?


四:数组和字符串的传递约定
数组的存储结构和编码方式在Fortran 和C#中是不同的,必须协调这两类参数的传递( 字符串可以看作是由字符组成的数组) 。
在计算机内存中数组的存储方式都是线性连续的,不同的是数组在Fortran 中的是列优先存储,而相应的在C#中是行优先存储。考虑到这个因素,在传递数组参数使用传址方式时,需要对数组做一个类似于矩阵转置的变换,使得两种计算机语言的数组存储方式统一。
integer an( 500,* )
int an[* , 500]

我想了解的是:
1、需要协调的二维数组包括哪些,比如FORTRAN代码中主程序范围内的,还是子程序范围内的,或者是我在我在FORTRAN中用到了IMSL动态链接库和其他动态链接库都要协调?


相对于数组的传递约定,协调处理字符串参数的则相对比较复杂。C#中表示字符串的结束的标志是\0,在Fortran 中却是不一样的,表示结束的方式是在最
右端添加空格,并且利用最右端的一个隐藏的参数来表示字符串的实际长度。另外,Fortran 语言的编码在文件路径名中是不支持中文字符集的,它默认的字符
集是ASCII 编码。而C#语言中是支持中文的,它所采用的字符集为Unicode 编码,为了使得两种语言能够进行字符串的传递,必须做相应的处理。当字符串参
数由Fortran 传回C#时,可利用C#中相应的函数将ASCII 字符转换为Unicode 字符。对于字符串由C#传入Fortran 时,可以在C#代码中添加一个整数型的参
数来表示字符串的长度。对于文件路径名由于Fortran不支持中文路径,所以在C#中编写的代码不要使用中文字符

我想了解的是:
1、协调字符串的具体代码及方法。
分享到:  微信微信
收藏收藏 点赞点赞 点踩点踩

58

帖子

9

主题

0

精华

熟手

F 币
256 元
贡献
163 点
沙发
 楼主| 发表于 2016-10-29 14:43:04 | 只看该作者
补充说明:
我的系统win7/8,编译器IVF2013/VS2013

490

帖子

4

主题

0

精华

大宗师

F 币
3298 元
贡献
1948 点

水王勋章元老勋章热心勋章

板凳
发表于 2016-10-29 15:20:56 | 只看该作者

回帖奖励 +5

zhuhuanlai 发表于 2016-10-29 14:43
补充说明:
我的系统win7/8,编译器IVF2013/VS2013

假定lz已经搞定C和C#混合编程,那么请参考下面的链接,在Fortran2003和2008标准下,利用iso c binding模块,fortran和c程序大体可以划上等号
Interoperability with C - The GNU Fortran Compiler
https://gcc.gnu.org/onlinedocs/g ... roperability-with-C

58

帖子

9

主题

0

精华

熟手

F 币
256 元
贡献
163 点
地板
 楼主| 发表于 2016-10-29 16:21:49 | 只看该作者
pasuka 发表于 2016-10-29 15:20
假定lz已经搞定C和C#混合编程,那么请参考下面的链接,在Fortran2003和2008标准下,利用iso c binding模块 ...

感谢您的及时热情的回复,很不好意思,我对C和C#了解都不多,哈哈。
iso c binding是Fortran2003标准新出的内部模块,好像专门用来和c混合编程,这个模块我也不太熟悉。不过您的建议提供了一个很好的思路,非常感谢!

1963

帖子

12

主题

5

精华

论坛跑堂

臭石头雪球

F 币
1357 元
贡献
574 点

美女勋章热心勋章星光勋章新人勋章贡献勋章管理勋章帅哥勋章爱心勋章规矩勋章元老勋章水王勋章

5#
发表于 2016-10-29 18:54:38 | 只看该作者
楼上说得很对,你看到的资料都是比较古老的版本,其中基本都是不规范的用法(IVF或部分编译器扩展支持)

现在,建议用 ISO_C_Binding 模块来统一与 C 语言混编。这样做的好处是规范,适合与所有编译器。
有关 ISO_C_Binding 可以参考《Modern Fortran Explained》第12章  Interoperability with C 与C语言交互
我对 C# 不懂,但是想来它调用 C 语言的 DLL 是非常简单的。如果你用了 ISO_C_Binding 那么接口就是和 C 的接口一样了。

部分问题:
1、如果我在FORTRAN代码中输入:
! DEC $ ATTRIBUTES StdCALL: : Filename
那在C#代码中需要输入CallingConvention Cdel还是CallingConvention StdCall?


当然是 StdCall ,两边要一致。但是用了 ISO_C_Binding 以后,不再用这个语句,那么 C# 应该用 cdel

2.关于FORTRAN调用约定的详细说明,在哪里能找到呢(我在帮助文件中找过,感觉介绍得不是特别详细)
帮助文档里有专门的 mix language 章节。

3.我只需要在FORTRAN中使用ALIAS 修改变量A的定义,而在C#不需要做任何修改就可以吗?
是的。C# 代码就视为 alias 里面的名字就好。
用了 ISO_C_Binding 以后,C# 视为 Bind( C ,Name="这里的名字" )

4、有哪些变量需要修改其定义,与动态链接库有关的变量是否都需要修改(我在FORTRAN中用到了IMSL动态链接库和其他动态链接库)?
你只需要修改想让 C# 操作的那些符号(变量或函数)就可以,内部使用了其他的函数库,不与混编问题发生关联。

5、我只需要在C#中使用ALIAS 修改变量A的定义,而在FORTRAN不需要做任何修改就可以吗?
6、两种解决方案中,哪种更加合适,比如运行更加稳定,不容易出错。
建议在 Fortran 里使用 ISO_C_Binding,以后不管是 C# 还是 Delphi 或者其他语言,均视为 C 接口
实际上,这些解决方案都可行,都稳定,只要方法得当,都不容易出错。就好像夫妻两个人不协调,那么丈夫迁就妻子,妻子迁就丈夫。都是可以的。
区别只是,ISO_C_Binding 是规范的。

7、如果我采用这种解决方案,变量A的已经是使用值传递了,那为什么还要在C#中再次声明呢?
混编就好像插头和插座,如果插头定义了是双孔,而插座依然是三孔,那还是无法匹配。
8、有哪些变量需要设置值传递,与动态链接库有关的变量是否都需要修改(我在FORTRAN中用到了IMSL动态链接库和其他动态链接库)?
同4

9.如果我采用这种解决方案,已经使用C#的ref 关键字,那为什么还要在FORTRAN中声明为[VALUE]?
同7

10、需要协调的二维数组包括哪些,比如FORTRAN代码中主程序范围内的,还是子程序范围内的,或者是我在我在FORTRAN中用到了IMSL动态链接库和其他动态链接库都要协调?
同4

11、协调字符串的具体代码及方法。
字符串建议 C# 里面用指针,Fortran 里面用 C_PTR 定义,用 C_F_Pointer 和 C_LOC 转换。因为这是标准的语法规范。

58

帖子

9

主题

0

精华

熟手

F 币
256 元
贡献
163 点
6#
 楼主| 发表于 2016-10-29 21:13:28 | 只看该作者
fcode 发表于 2016-10-29 18:54
楼上说得很对,你看到的资料都是比较古老的版本,其中基本都是不规范的用法(IVF或部分编译器扩展支持)

...

感谢您如此详细的回复,非常感谢!
有关 ISO_C_Binding 的资料全是英文的,有中文版的资料推荐吗,
FORTRAN2003的教材也没有找到相关的中文资料。

58

帖子

9

主题

0

精华

熟手

F 币
256 元
贡献
163 点
7#
 楼主| 发表于 2016-10-29 21:16:45 | 只看该作者
pasuka 发表于 2016-10-29 15:20
假定lz已经搞定C和C#混合编程,那么请参考下面的链接,在Fortran2003和2008标准下,利用iso c binding模块 ...

您能推荐一些关于C和C#混合编程的例子,或者相关资料吗,我对这两种语言的混合编程实在是不了解。
先谢谢您了。

1963

帖子

12

主题

5

精华

论坛跑堂

臭石头雪球

F 币
1357 元
贡献
574 点

美女勋章热心勋章星光勋章新人勋章贡献勋章管理勋章帅哥勋章爱心勋章规矩勋章元老勋章水王勋章

8#
发表于 2016-10-30 22:03:56 | 只看该作者
确实没有中文资料。
本论坛“编程工具”区,混编分类下面有一些帖子,你或许可以参考。

490

帖子

4

主题

0

精华

大宗师

F 币
3298 元
贡献
1948 点

水王勋章元老勋章热心勋章

9#
发表于 2016-10-31 16:20:11 | 只看该作者
zhuhuanlai 发表于 2016-10-29 21:16
您能推荐一些关于C和C#混合编程的例子,或者相关资料吗,我对这两种语言的混合编程实在是不了解。
先谢谢 ...

抱歉,我已经好久不玩vc和c#,照理msdn肯定有相关内容,vs帮助文档也会有相关范例代码
iso c binding的建议仅供参考,目前来看针对gcc系列编译器优势明显,若是vs+ivf的搭配不见得事半功倍

712

帖子

4

主题

0

精华

大师

农村外出务工人员

F 币
607 元
贡献
311 点

新人勋章爱心勋章水王勋章元老勋章热心勋章

10#
发表于 2016-10-31 19:22:44 | 只看该作者
iso_c_binding 在 vs和ivf 也很顺畅。
您需要登录后才可以回帖 登录 | 极速注册

本版积分规则

捐赠本站|Archiver|关于我们 About Us|小黑屋|Fcode ( 京ICP备18005632-2号 )

GMT+8, 2024-4-26 20:24

Powered by Tencent X3.4

© 2013-2024 Tencent

快速回复 返回顶部 返回列表