Dll编译器之间的兼容性 [英] Dll compatibility between compilers

查看:185
本文介绍了Dll编译器之间的兼容性的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

有什么方法可以让c ++ dll与不同的编译器建立兼容?类可以有工厂方法创建和销毁,所以每个编译器可以使用自己的新/删除(因为不同的运行时有自己的堆)。

Is there some way to make c++ dlls built with diffrent compilers compatible with each other? The classes can have factory methods for creation and destruction, so each compiler can use its own new/delete (since diffrent runtimes have there own heaps).

我试过下面的代码,但它崩溃的第一个成员方法:

I tried the following code but it crashed on the first member method:

interface.h

interface.h

#pragma once

class IRefCounted
{
public:
    virtual ~IRefCounted(){}
    virtual void AddRef()=0;
    virtual void Release()=0;
};
class IClass : public IRefCounted
{
public:
    virtual ~IClass(){}
    virtual void PrintSomething()=0;
};

使用VC9,test.exe编译的test.cpp

test.cpp compiled with VC9, test.exe

#include "interface.h"

#include <iostream>
#include <windows.h>

int main()
{
    HMODULE dll;
    IClass* (*method)(void);
    IClass *dllclass;

    std::cout << "Loading a.dll\n";
    dll = LoadLibraryW(L"a.dll");
    method = (IClass* (*)(void))GetProcAddress(dll, "CreateClass");
    dllclass = method();//works
    dllclass->PrintSomething();//crash: Access violation writing location 0x00000004
    dllclass->Release();
    FreeLibrary(dll);

    std::cout << "Done, press enter to exit." << std::endl;
    std::cin.get();
    return 0;
}

使用g ++编译a.cpp
g ++。exe -shared c .cpp -o c.dll

a.cpp compiled with g++ g++.exe -shared c.cpp -o c.dll

#include "interface.h"
#include <iostream>

class A : public IClass
{
    unsigned refCnt;
public:
    A():refCnt(1){}
    virtual ~A()
    {
        if(refCnt)throw "Object deleted while refCnt non-zero!";
        std::cout << "Bye from A.\n";
    }
    virtual void AddRef()
    {
        ++refCnt;
    }
    virtual void Release()
    {
        if(!--refCnt)
            delete this;
    }

    virtual void PrintSomething()
    {
        std::cout << "Hello World from A!" << std::endl;
    }
};

extern "C" __declspec(dllexport) IClass* CreateClass()
{
    return new A();
}

编辑:
我将以下行添加到GCC CreateClass方法,文本被正确地打印到控制台,所以它defenatly函数调用它杀死它。

I added the following line to the GCC CreateClass method, the text was correctly printed to the console, so its defenatly the function call thats killing it.

std::cout << "C.DLL Create Class" << std::endl;

我想知道,COM如何保持跨语言的二进制兼容性,因为它基本上是所有类与继承(虽然只有单一),因此虚拟函数。如果我不能有重载的操作符/函数,只要我能保持基本的OOP东西(即类和单继承),我不会massivly困扰。

I was wondering, how does COM manage to maintain binary compatibility even across languages, since its basicly all classes with inheritence (although only single) and therefore virtual functions. I'm not massivly bothered if I cant have overloaded operators/functions as long as I can maintain the basic OOP stuff (ie classes and single inheritence).

推荐答案

如果你降低你的期望并坚持使用简单的函数,你应该能够混合使用不同编译器创建的模块。

You should be able to mix modules built with different compilers if you lower your expectations and stick to simple functions.

类和虚函数behave是由C ++标准定义的,但是实现的方式取决于编译器。在这种情况下,我知道VC ++构建具有虚拟函数的对象,在对象的前4个字节中有一个vtable指针(我假设为32位),并指向一个指向方法入口的指针表

The way classes and virtual functions behave is defined by the C++ standard, but the way that's implemented is up to the compiler. In this case, I know that VC++ builds objects which have virtual functions with a "vtable" pointer in the first 4 bytes of the object (I'm assuming 32-bit), and that points to a table of pointers to the method entry points.

所以行: dllclass-> PrintSomething();
实际上等于例如:

So the line: dllclass->PrintSomething(); is actually equivalent to something like:

struct IClassVTable {
    void (*pfIClassDTOR)           (Class IClass * this) 
    void (*pfIRefCountedAddRef)    (Class IRefCounted * this);
    void (*pfIRefCountedRelease)   (Class IRefCounted * this);
    void (*pfIClassPrintSomething) (Class IClass * this);
    ...
};
struct IClass {
    IClassVTable * pVTab;
};
(((struct IClass *) dllclass)->pVTab->pfIClassPrintSomething) (dllclass);

如果g ++编译器以与MSFT VC ++不同的方式实现虚函数表 - 是自由的,仍然符合C ++标准 - 这将只是崩溃,因为你已经证明。 VC ++代码期望函数指针在内存中的特定位置(相对于对象指针)。

If the g++ compiler is implementing the virtual function tables in any way differently from MSFT VC++ -- as it is free to do and still be conformant to the C++ standard -- this will just crash as you've demonstrated. The VC++ code expects the function pointers to be in particular places in memory (relative to the object pointer).

继承会变得更复杂,真的,真的,复杂具有多重继承和虚拟继承。

It gets more complicated by inheritance, and really, really, complicated with multiple inheritance and virtual inheritance.

Microsoft已经非常公开VC ++实现类的方式,所以你可以编写依赖它的代码。例如,由MSFT分发的许多COM对象头在头中具有C和C ++绑定。 C绑定暴露了它们的vtable结构,像我上面的代码。

Microsoft has been very public about the way VC++ implements classes, so you can write code that depends on it. For example, a lot of COM object headers distributed by MSFT have both C and C++ bindings in the header. The C bindings expose their vtable structure like my code above does.

另一方面,GNU - IIRC - 已经打开了使用不同的实现在不同的选项发布,只是保证用它的编译器编译的程序(只有!)将符合标准的行为,

On the other hand, GNU -- IIRC -- has left open the option of using different implementations in different releases, and just guaranteeing the programs built with it's compiler (only!) will conform to the standard behaviour,

简单的答案是坚持使用简单的C风格函数, POD结构(普通数据;即没有虚拟函数)和指向不透明对象的指针。

The short answer is to stick to simple C-style functions, POD structures (Plain Old Data; i.e., no virtual functions), and pointers to opaque objects.

这篇关于Dll编译器之间的兼容性的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆