Fortran Coder

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

[混编] c++向Fortran的dll传递字符串发生“访问冲突”

[复制链接]

5

帖子

2

主题

0

精华

入门

F 币
35 元
贡献
11 点
跳转到指定楼层
楼主
发表于 2016-11-3 23:09:50 | 只看该作者 |只看大图 回帖奖励 |正序浏览 |阅读模式
根据群主大人的指点(网址:http://bbs.fcode.cn/forum.php?mo ... &page=1#pid6531),我成功地再现了他的代码。但是,当我编写我的代码时,却发生了奇怪的错误,如下:(1)最主要的错误是进入dll的子过程时提示“cpp_main.exe 中的 0x5d7005a9 (vlhm.dll) 处最可能的异常: 0xC0000005: 读取位置 0x00000021 时发生访问冲突
cpp_main.exe 中的 0x5d7005a9 (vlhm.dll) 处有未经处理的异常: 0xC0000005: 读取位置 0x00000021 时发生访问冲突”。如图:

(2)非常“诡异”的是:群主给的代码,不会提示说要加“@8”,但我的代码,如果和示例代码一样,写成“subroutine vlhm( pfilename , lens ) Bind(C,Name="vlhm")”的话,却提示“无法解析”(可是我并没有改动示例代码啊...)。如图:

闲话少说,下面上代码!
(1)c++主程序的代码:
[Fortran] 纯文本查看 复制代码
#include "stdafx.h"
#include <stdio.h>
#include <string.h>

extern "C" {void _stdcall   vlhm(char *,int); }
//extern "C" {void vlhm(char *,int); }
int _tmain(int argc, _TCHAR* argv[])
{
  char *inputfile= "C:\\Users\\www\\Desktop\\31005700.tem";
  //char *inputfile;
  //char str[] = "C:\\Users\\www\\Desktop\\\\31005700.tem";
  //inputfile=&str[0];
  vlhm(inputfile,strlen(inputfile));
  return 0;
}


(2)Fortran的DLL代码:
[Fortran] 纯文本查看 复制代码
subroutine vlhm( pfilename , lens ) Bind(C,Name="vlhm")
!!!subroutine vlhm(pfilename,lens) Bind(C,Name="vlhm@8")

!DEC$ ATTRIBUTES DLLEXPORT::vlhm


  use ,Intrinsic::ISO_C_Binding


  implicit none

  type(C_PTR) , value :: pfilename !c++主程序中传递进来的“Inputfile”变量,是C语言的指针
  integer::lens                                      !传入的字符串长度
  character(len=lens),pointer::filename                     !这是Fortran的字符串

  call c_f_pointer( pfilename , filename )                   !把c语言的指针转换成fortran字符串

  write(*,*)filename

end subroutine



aaa.png (43.11 KB, 下载次数: 356)

错误(1)

错误(1)

bbb.png (3.11 KB, 下载次数: 371)

错误(2-1)

错误(2-1)

ccc.png (17.37 KB, 下载次数: 352)

错误(2-2)

错误(2-2)
分享到:  微信微信
收藏收藏 点赞点赞 点踩点踩

58

帖子

9

主题

0

精华

熟手

F 币
256 元
贡献
163 点
15#
发表于 2016-11-22 14:14:30 | 只看该作者
pasuka 发表于 2016-11-21 09:10
可惜了,看来ls对于程序编译还是一知半解。。sigh

哈哈,我属于非专业程序猿,算是半吊子,见笑了

490

帖子

4

主题

0

精华

大宗师

F 币
3298 元
贡献
1948 点

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

14#
发表于 2016-11-21 09:10:43 | 只看该作者
zhuhuanlai 发表于 2016-11-19 12:10
感谢您的回复,我想用到的是FORTRAN输出的DLL文件。

可惜了,看来ls对于程序编译还是一知半解。。sigh

58

帖子

9

主题

0

精华

熟手

F 币
256 元
贡献
163 点
13#
发表于 2016-11-19 12:10:36 | 只看该作者
pasuka 发表于 2016-11-18 08:47
给点干货吧
Fortran代码
[mw_shl_code=fortran,true]module mixcompile

感谢您的回复,我想用到的是FORTRAN输出的DLL文件。

490

帖子

4

主题

0

精华

大宗师

F 币
3298 元
贡献
1948 点

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

12#
发表于 2016-11-18 08:47:41 | 只看该作者
给点干货吧
Fortran代码
[Fortran] 纯文本查看 复制代码
module mixcompile
use iso_c_binding
implicit none
contains
    subroutine cpp_print(cpp_char, n) bind(c, name="f90print")
        use iso_c_binding
        implicit none
        type(c_ptr), value:: cpp_char
        integer(c_int), value:: n

        character(len=n), pointer:: f_string
        call c_f_pointer(cpp_char, f_string)
        write(*, '("Length of string:", 1x, I4)')n
        write(*, *)f_string
    end subroutine
end module

c++代码
[C++] 纯文本查看 复制代码
#include <string>

extern "C" {void f90print(const char*, int);};

int main(int argc, char *argv[])
{
    std::string s{"0123456789"};
    f90print(s.c_str(), s.size());
    for(int i=0; i<argc; i++){
        s = argv[i];
        f90print(s.c_str(), s.size());
    }
    return 0;
}

编译命令
[Bash shell] 纯文本查看 复制代码
g++ a.f90 b.cc -lgfortran -o example

58

帖子

9

主题

0

精华

熟手

F 币
256 元
贡献
163 点
11#
发表于 2016-11-17 21:10:30 | 只看该作者
本帖最后由 zhuhuanlai 于 2016-11-17 21:15 编辑

您好,请问您在再现群主的代码时,出现过图一问题吗?

我把int _tmain(int argc, _TCHAR* argv[])   改成
int main(int argc, _TCHAR* argv[])         出现了同样的错误

我改成
int main()
去掉里面的参数后又出现图二错误:

如果您方便,请帮忙分享一下您的再现方法,非常感谢?


221444jpbmq0lw0m0rvio9.jpg (292.27 KB, 下载次数: 287)

图一

图一

X{GX@96334{Q{~W2)ZIV459.jpg (228.75 KB, 下载次数: 286)

图二

图二

58

帖子

9

主题

0

精华

熟手

F 币
256 元
贡献
163 点
10#
发表于 2016-11-16 19:18:48 | 只看该作者
fcode 发表于 2016-11-15 23:03
1. 你不能全部照抄别人的例子,例如这个例子,是因为提问者的“甲方”要求,必须使用 stdcall。
2. 而 ISO_ ...

感谢您在这么晚的时间还给出了如此详尽的指点!

拜读了您的指点后,豁然开朗,Fortran有您更精彩!

1963

帖子

12

主题

5

精华

论坛跑堂

臭石头雪球

F 币
1357 元
贡献
574 点

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

9#
发表于 2016-11-15 23:03:08 | 只看该作者
1. 你不能全部照抄别人的例子,例如这个例子,是因为提问者的“甲方”要求,必须使用 stdcall。
2. 而 ISO_C_Binding 只能用“规范的语言”写 c 的调用协定,而不能写 stdcall 调用协定。
3. 因此,这个例子的提问者没有办法,只能使用 ATTRIBUTES 来实现 stdcall
4. 如果你只是要和 C 进行混编,而没有“必须使用 stdcall”的要求。那么 Bind( C 就可以实现
5. 我对IVF各个版本具体支持什么扩展特性并不十分清楚。毕竟我用过的也就那么一两个版本,而不会每个版本都用。
6. 去掉 Bind(C 的话,会有两个影响:
   a. 不能默认 c调用协定,而使用 IVF协定(当然你可以用 ATTRIBUTES 更改协定,只不过低版本的IVF不允许 Bind C 和 ATTRIBUTES并存,因为两者冲突)
   b. 不能默认 c的“符号修饰”(比如 name(x) 被修饰为 _name@4 或者 _name),相当于 Alias。
   除了上面两个差别,Bind( C )没有其他作用。关于参数传递约定,数组/字符串传递,请遵循 ISO_C_Binding 约定。

其实混编就那么点东西
Bind(C 是规范的,用来起到默认 C 协定,及默认 C 符号修饰的目的。
而 ATTRIBUTES 和 ALIAS 是扩展语法。作用其实与 Bind C 一样。
区别,仅仅是规范和不规范而已。

58

帖子

9

主题

0

精华

熟手

F 币
256 元
贡献
163 点
8#
发表于 2016-11-15 12:39:52 | 只看该作者
本帖最后由 zhuhuanlai 于 2016-11-15 12:43 编辑

去掉 Bind(C ,Name="vlhm")
然后 ATTRIBUTES 里面写 stdcall 和 alias.
stdcall 和 alias.是IVF扩展的写法,相当于堆栈清理和命名约定不再通过 ISO_C_Binding。
但是如果去掉Bind(C ,Name="vlhm"),只使用use ,Intrinsic::ISO_C_Binding,在参数传递约定和数组/字符串传递约定还有效吗?

另外,我是2013VS+2013IVF,需要哪个版本的编译器才支持呢?

1963

帖子

12

主题

5

精华

论坛跑堂

臭石头雪球

F 币
1357 元
贡献
574 点

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

7#
发表于 2016-11-14 22:44:27 | 只看该作者
看 5 楼
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 极速注册

本版积分规则

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

GMT+8, 2024-5-7 02:52

Powered by Tencent X3.4

© 2013-2024 Tencent

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