首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >使用不同C/C++运行库的exe和dll之间的接口

问使用不同C/C++运行库的exe和dll之间的接口
EN

Stack Overflow用户
提问于 2012-07-22 14:40:27
回答 1查看 2.4K关注 0票数 4

给定:可执行文件使用dll。它们有不同的c/c++运行时。它们之间的接口存在哪些限制?此外,它们使用相同的编译器,相同的Boost版本(但不同的预编译boost库)。

我理解不同的运行时可以有不同的堆。因此,delete必须对应于同一堆中的new。

最重要的是,我们不能通过接口STL对象传递,因为当我们构建exe STL对象与一个运行时以及在构建dll时,同一个对象(如果通过引用传递或通过接口复制)将与另一个运行时链接。而另一个运行时可以具有该对象的不同实现。

让我们考虑一下情况:

  1. 我认为以下几点是安全的。Dll导出函数,该函数具有参数:引用导出的用户定义类,其中包含作为成员的私有STL类。Dll为此对象分配内存。当要删除该对象时,Exe调用该对象的释放方法。
  2. 我认为下面这是不安全的。用户定义的类在exe中实例化,并通过exe/dll接口传递。该类包含作为成员的私有STL类。此用户类的exe和dll共享头/实现文件。当该类构建在单独的项目中时,将使用不同的STL实现。例如,string::size()的不同实现(来自不同的运行时)将应用于内存中的同一个对象。
  3. 我认为以下几点是安全的。用户定义的类在exe中实例化,并通过exe/dll接口传递。这个类不依赖于标准库,它只使用原始的C++类型。此用户类的exe和dll共享头/实现文件。另外,我们必须控制新的和删除的对应于同一个堆。例如,我们可以重载新/删除,以便它们使用::GetProcessHeap。
  4. 我认为以下是不安全的:通过exe/dll接口传递boost对象,因为它们可以依赖于标准库类。此外,delete可能与new的堆不对应。
  5. 我认为以下内容是不安全的:即使我们通过exe/dll接口传递boost对象,并且它们不依赖于标准库类,但不只是作为标头实现--但对象可以用一个boost库创建(一个运行时),而可以与另一个boost库一起使用(对于另一个运行时)。此外,delete可能与new的堆不对应。

此外,我还想使用一些智能指针来传递对对象的引用(在第3项中提到),从exe传递到dll,从dll传递到exe。我认为这个智能指针还应该重载new/delete,以便从默认进程堆中分配引用计数器。当尝试删除指向对象时,它将调用该对象重载的delete (如item3中的)。

对于第1项中的对象,我希望使用自定义智能指针,它将调用指向对象的释放方法(作为带有自定义发布的boost::shared_ptr )。

没有提到哪些问题?请纠正我。

EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2012-07-22 20:48:34

对您的问题的一般回答是:对从EXE/DLL接收的对象进行处理是安全的,如果实际操作不依赖于运行时。例如vtable调用、函数指针调用、DLL中的显式函数调用。

依赖于运行时的东西(来自头文件的内联方法,任何关于STL对象布局的假设,等等)都不安全。

回到你的例子:

  1. 如果您调用Release()方法,您应该小心,并确保您将从DLL调用Release()的实现,而不是调用由生成EXE文件的编译器创建的另一个实现。确保它是虚拟的最简单的方法是使Release()虚拟,这样调用始终是使用vtable (由DLL提供)的方法指针进行的调用。
  2. 对,STL中的内联方法(如string::size() )将在这里引起问题。
  3. 正确的。如果new/delete都被重载以使用GetProcessHeap(),则代码将工作。
  4. 一般来说,是的。特别是,请参阅所需的boost类的实现。
  5. 如果它们不依赖于STL,并且您确信这两个编译器的内存占用都是相同的,并且您已经提供了自定义的new/delete(),那么通常不会出现问题(参见下面的备注)。

备注:

有一些低概率的事情可能会导致上面没有提到的问题:

  1. 如果使用不同的编译器,默认情况下,它们可能使用不同的调用约定(cdecl/stdcall)。
  2. 默认对齐选项也可能不同,从而导致不同的内存布局。
  3. 如果您从DLL中抛出异常,则具有不同运行时的exe可能不会捕获它们,而是会崩溃。
  4. 用DLL导入/导出属性标记这些方法,并确保它们没有内联,这是一个相当麻烦的问题。此外,如果您使用的是不同的编译器,则C++名称损坏算法可能会有所不同。

在总结了一些事情之后,建议看看如何在Microsoft中实现这些东西,并设计一些类似的东西。即将EXE/DLL交互限制在:

  1. 接口。也就是说,只有纯虚拟方法的C++类。使用虚拟版本()删除对象。
  2. 简单明确的结构。确保所有编译器的对齐选项匹配。如果您想使用非平凡的结构,并且使用的是不同的编译器,最好是偏执,并将检查如下: 结构MyStruct {. };C_ASSERT(MyStruct) == .;C_ASSERT(MyStruct,MyMember) =.;
  3. 类C函数传递和/或返回接口的指针。
  4. 不要抛出EXE调用的方法的异常
票数 4
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/11601192

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档