通过 C 接口传递C++ I/O 类时特定于编译器的问题

Compiler-specific issues with passing C++ i/o classes through C interfaces

本文关键字:编译器 问题 接口 C++ 通过      更新时间:2023-10-16

我有一个问题,似乎是由我的编译器引起的。 当我使用 Mingw 编译 DLL 时,一切似乎都很好。 当我使用 MSVC 编译 DLL 时,代码似乎在createMdl某处阻塞。 该进程的 CPU 使用率为 0%,我永远不会从下面的函数createMdl函数调用中返回。

这段代码在有点大的远程环境中运行,所以为了在我的机器上进行调试,我创建了一个描述以下问题的框架。 不幸的是,这段代码也没有表现出我所看到的行为,但确实描述了我正在尝试做的事情。

应用:

#include <boost/asio.hpp>
#include <boost/thread.hpp>
#include <windows.h>
int main()
{
boost::asio::io_service io;
boost::asio::io_service::work work(io);
boost::thread t(boost::bind(&boost::asio::io_service::run, &io));
HMODULE h = LoadLibrary("MyLib.dll");
typedef void (*createMdl_fn)(void*);
createMdl_fn createMdl = (createMdl_fn)GetProcAddress(h, "createMdl");
createMdl((void*)&io);
}

.DLL:

#include <boost/asio.hpp>
extern "C" __declspec(dllexport) void __cdecl createMdl(void* io)
{
boost::asio::io_service*       io_svc = (boost::asio::io_service*)io;
boost::asio::ip::udp::endpoint endpoint(boost::asio::ip::udp::v4(), 12345);
boost::asio::ip::udp::socket   sock(*io_svc, endpoint);
char* buf = new char[256];
sock.async_receive_from( boost::asio::buffer(buf, 256),
endpoint,
[buf](const boost::system::error_code& e,
std::size_t b){});
}

你能看出这种方法的缺陷吗? 这种方法是否有任何不稳定之处?如果您认为io_service(void*)铸造是一个问题,那么在使用GetProcAddress的情况下您将如何做到这一点? 请注意,无论使用哪个编译器来编译应用程序,我都会得到相同的行为。

我能看到的最大问题是,如果我使用新版本的 boost 重新编译库,io_service的定义可能会改变,这可能会导致问题,但这并不能解释我现在遇到的问题。

如果在不同的编译单元/DLL/可执行文件/其他任何对象之间传递C++对象,则必须使用相同的编译器构建它们,否则绝对可以保证一切都会爆炸并燃烧起来。

不同的C++编译器具有非常不兼容的 ABI。这与 C 编译器形成鲜明对比,C 编译器通常在任何给定平台上都有兼容的 ABI,并且可以安全地混合和匹配。

在这种情况下,无需强制转换指向 void* 的指针或将函数声明为 extern "C"。(使用 GetProcAddress 的函数除外(。

仅当将编译器之间共享的数据限制为内置类型和 C 兼容结构时,才能使用不同的C++编译器。永远不要使用具有虚函数或访问说明符、指向成员的指针或标准库类型的类 — 简而言之,没有任何C++与 C 有什么不同。如果您确实使用不同的C++编译器,则必须将函数和对象声明为extern "C"

将一个供应商的C++编译器与来自不同供应商的 C 编译器一起使用通常不是问题。