delphi 调用 vc 编译的dll, 注册回调函数后,在回调函数中打印字符串出现乱码

最近遇到个比较奇葩的问题,场景是这样

1、上位机程序是用 delphi 编写的

2、动态库是用 vc++ 编写的

3、动态库里面有个回调函数机制,使用用DLL时,需要注册回调函数,回调函数的参数有一个指向结构体的指针

4、上位机实现的回调函数会打印指针内的内容

5、上位机调用debug版的DLL时,内容显示正确,而调用 release 版的 DLL 时,内容显示的是乱码

 

解决过程入下

1、对比 DLL 中 debug 和 relese 的编译选项,找出影响这个结果的那一项

2、最后发现是 “属性”->“C/C++”->“常规”->“调试信息格式” 这一项 出现的影响,

debug 版的值是  “用于“编辑并继续”的程序数据库 (/ZI)”

release 版的值是 “程序数据库 (/Zi)”

3、如果把release版的值也修改成   “用于“编辑并继续”的程序数据库 (/ZI)”, 则上位机显示得内容也变得正常了

但是为什么这两个的值不同会导致内容显示也不同,这个就不清楚了。

 

由于实在是不甘心,就走到这一步,感觉问题不一定在DLL,我又从上位机那里入手

1、从现象来看,内容打印错误,但是结构体大小是正确的

2、问题可能出现在结构体在内存中的排布顺序

3、能影响到参数在内存中的排布顺序的,很可能就是调用约定了

4、检查回调函数的声明和定义,都没有显式地声明调用约定,估计问题就出在这里了

5、默认情况下,vc++如果没有显式声明调用约定,则默认的调用约定就是 _cdecl

6、而delphi的调用则是 register

7、尝试着在delphi 上位机中显式声明调用约定 _cdecl ,重新编译

8、再次执行上位机,显示内容正确!

 

回顾下来,就是因为没有在 delphi 中指定调用约定,导致了这次的 “乱码” 事故,大家往后在写代码的时候要多多注意才是。

后面去查了一下,关于编译选项的说明

/Z7、/Zi、/ZI(调试信息格式)

  • 2008/08/18

更新:2007 年 11 月

选择为程序创建的调试信息的类型,并选择是将此信息保存在对象 (.obj) 文件还是程序数据库 (PDB) 中。

复制

/Z{7|i|I}

备注

下表描述了这些选项。


  • 不产生任何调试信息,因此编译较快。

  • /Z7
    生成包含用于调试器的完整符号调试信息的 .obj 文件。符号调试信息包括变量的名称和类型以及函数和行号。不会生成任何 .pdb 文件。

    对于第三方库的发布者,不生成 .pdb 文件是一个优点。但是,在链接和调试期间,用于预编译头的 .obj 文件是必需的。如果 .pch 对象文件中只有类型信息(没有代码),则还必须使用 /Yl(为调试库插入 PCH 引用) 进行编译。

  • /Zi
    产生包含用于调试器的类型信息和符号调试信息的程序数据库 (PDB)。符号调试信息包括变量的名称和类型以及函数和行号。

    /Zi 不影响优化。但是,/Zi 的确暗示了 /debug;有关更多信息,请参见 /DEBUG(生成调试信息)

    类型信息放置在 .pdb 文件而不是 .obj 文件中。

    可以将 /Gm(启用最小重新生成) 和 /Zi 结合使用,但使用 /Z7 编译时不能使用 /Gm

    使用 /Zi 和 /clr 编译时,DebuggableAttribute 属性将不会被放入程序集元数据中;如果要使用该属性,则必须在源代码中指定它。该属性可影响应用程序的运行时性能。有关 Debuggable 属性如何影响性能以及如何减轻性能影响的更多信息,请参见令映像更易于调试

  • /ZI
    以支持“编辑并继续”功能的格式产生如上所述的程序数据库。如果想使用“编辑并继续”调试,则必须使用此选项。因为大多数优化与“编辑并继续”不兼容,所以使用 /ZI 会禁用代码中的所有 #pragma optimize 语句。

    /ZI 会导致在编译中使用 /Gy(启用函数级链接)

    /ZI 与 /clr(公共语言运行库编译) 不兼容。

    表 1
    说明:

    /ZI 只可用于面向 x86 的编译器中;此编译器选项不可用于面向 x64 或 Itanium 处理器系列 (IPF) 的编译器中。

编译器将程序数据库命名为 项目.pdb。如果编译没有项目的文件,则编译器将创建名为 VCx0.pdb. 的数据库,其中 x 是正在使用的 Visual C++ 的主版本。编译器将 PDB 的名称嵌入每个使用此选项创建的 .obj 文件中,从而使调试器了解符号和行号信息的位置。当使用此选项时,.obj 文件将较小,因为调试信息存储在 .pdb 文件中而不是 .obj 文件中。

如果从使用此选项编译的对象创建库,则在将库链接到程序时,关联 .pdb 文件必须可用。因此,如果发布此库,就必须发布 PDB。

若要不使用 .pdb 文件创建包含调试信息的库,必须选择编译器的 C 7.0 兼容 (/Z7) 选项。如果使用预编译头选项,则预编译头和其他源代码的调试信息都放在 PDB 中。指定了“程序数据库”选项时将忽略 /Yd 选项。

原因可能和 “禁用代码中的所有 #pragma optimize 语句” 这个有关,深层次的原因目前还想不出来。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值