deviseC API的最佳方法是处理传递与C运行时相关的“对象”(FILE *,由malloc返回的指针等)的问题。 例如,如果两个DLL与不同版本的运行时间链接,我的理解是,您不能安全地将一个DLL从一个DLL传递给另一个DLL。
是唯一的解决scheme使用Windows相关的API(这是保证在DLL工作)? C API已经存在,并且已经成熟,但是主要是由unixdevise的(当然还是要在unix上工作)。
你要求C而不是C ++解决方案。
在C中做这种事的通常方法是:
设计模块API,不需要CRT对象。 获取通过原始C类型通过的东西 – 即让消费者加载文件,只是传递给你的指针。 或者,让消费者传递一个完全合格的文件名,在内部打开,阅读和关闭。
其他c模块,MS机柜SD以及OpenSSL库iirc的一部分使用了一种方法,让消费应用程序将指针传递给初始化函数。 所以,任何传递FILE *的API都会在初始化过程中取得一个指向结构的指针,这个结构的指针匹配fread,fopen等特征。当处理外部文件时,dll总是使用传入的功能而不是CRT功能。
用这样的一些简单的技巧,你可以使你的C DLLs接口完全独立于主机CRT,或者实际上要求主机用C或C ++编写。
现有的答案都是正确的:在Windows上给出以下内容:您有两个DLL,每个都静态链接到两个不同版本的C / C ++标准库。
在这种情况下,您不应该将指针传递给由另一个DLL中的C / C ++标准库创建的结构。 原因在于这两个C / C ++标准库实现之间的结构可能不同。
另一件你不应该做的就是释放一个由new或malloc分配的指针。 堆管理器也可以被不同地实施。
请注意,您可以使用DLL之间的指针 – 它们只是指向内存。 这是免费的问题。
现在,你可能会发现这是有效的,但如果是这样的话,那么你只是运气。 这很可能会在未来导致你的问题。
你的问题的一个可能的解决方案是动态链接到CRT 。 例如,您可以动态链接到MSVCRT.DLL。 这样你的DLL将总是使用相同的CRT。
请注意,我建议在DLL之间传递CRT数据结构并不是最佳实践。 你可能想看看你是否可以更好地考虑事情。
请注意,我不是Linux / Unix专家,但是您在这些操作系统上也会遇到同样的问题。
不同的运行时间的问题是不可解的,因为FILE *结构属于Windows系统上的一个运行时。
但是,如果你写一个小封装界面你做了,它并没有真正的伤害。
stdcall IFile* IFileFactory(const char* filename, const char* mode); class IFile { virtual fwrite(...) = 0; virtual fread(...) = 0; virtual delete() = 0; }
这是保存在跨越dll边界通过,并没有真正的伤害。
PS:小心,如果你开始在DLL边界抛出异常。 如果你在Windows操作系统上实现了一些设计方法,但是在其他方面会失败的话,这将会很安静。
如果C API存在并且已经成熟,那么使用纯粹的Win32 API来绕过CRT就可以让你获得一半的成果。 另一半是确保DLL的用户使用相应的Win32 API函数。 这会使您的API在使用和文档中的可移植性降低。 另外,即使你用这种内存分配方式,CRT函数和Win32函数都处理void *,你仍然遇到文件问题 – Win32 API使用句柄,而对FILE结构一无所知。
我不太清楚FILE *有什么限制,但是我认为这个问题和跨模块的CRT分配是一样的。 MSVCRT内部使用Win32来处理文件操作,同一进程中的每个模块都可以使用底层文件句柄。 可能不起作用的是关闭由另一个模块打开的文件,这涉及到在可能不同的CRT上释放FILE结构。
我会做什么,如果更改API仍然是一个选项,导出清理功能的DLL中创建的任何可能的“对象”。 这些清理函数将以与在该DLL中创建的方式相对应的方式来处理给定对象的处置。 这也将使DLL在使用方面绝对便携。 唯一的担心就是确保DLL的用户确实使用清理函数,而不是普通的CRT函数。 这可以使用几个技巧,值得另一个问题…