在C ++中处理C库匿名结构类型

时间:2012-08-13 11:48:22

标签: c++ c gcc name-mangling anonymous-struct

我们有一个庞大的旧C ++应用程序,其中包含许多遗留代码和一些用C编写的外部库。这些库很少更新 - 只有当我们发现错误并且供应商提供补丁时。上周发生了一个库,在集成新版本时,我们发现如果我们不在本地修改库(我们显然使用上一版本),我们的构建就会出现这个错误消息:

non-local function ‘static E* MyCls::myFct(<anonymous struct>*)’ uses anonymous type

这是因为库声明了许多这样的句柄类型:

#define _Opaque struct {unsigned long x;} *

typedef _Opaque    Handle;
typedef _Opaque    Request;
我们在一些类的函数签名中使用的

class MyCls {
public:
    static void* myFct(Handle handle);
    ...
}

这会产生上面的错误,因为编译器无法为函数创建正确的名称错位名称,因为_Opaque结构没有名称。

我们目前的解决方法是修补库头文件,明确地给结构命名:

//#define _Opaque struct {unsigned long x;} * //Replaced by typedef below!
typedef struct __Opaque {unsigned long x;} * _Opaque;

这显然很糟糕,因为如果可能的话我们不想触摸库。另一个更糟糕的选择是将所有函数签名中的类型转换为void*并将它们转换回各自的类型。并且在纯C中重写每个受影响的函数是最糟糕的选择...

所以,我的问题是:有没有比修补图书馆更好的选择?我有一个简单的解决方案吗?解决这个问题的最佳方法是什么?

4 个答案:

答案 0 :(得分:3)

您可以通过对#define行的最小更改来完成此操作,利用7.1.3中的规则:8 声明声明的第一个typedef-name 类类型(或枚举类型)用于表示类型(或枚举类型)仅用于链接目的

#define MAKE_DUMMY2(line) dummy_ ## line
#define MAKE_DUMMY(line) MAKE_DUMMY2(line)
#define _Opaque struct {unsigned long x;} MAKE_DUMMY(__LINE__), *

这为HandleRequest等提供了最小的联系。

答案 1 :(得分:1)

您可以通过声明仅包含这些元素的新类型来引入名称。将这些类型用于参数。

namespace MON {
struct t_handle {
  Handle handle;
};

class MyCls {
public:
    static void* myFct(t_handle handle);
    ...
};
}

答案 2 :(得分:1)

如果您愿意在界面上修改方法,则可以比void *稍微好一点:

struct CHandle {
    void *p;
    CHandle(void *p): p(p) { }
};
struct CRequest {
    void *p;
    CRequest(void *p): p(p) { }
};

static CHandle make(Handle handle) { return CHandle(handle); }
static Handle get(CHandle handle) { return static_cast<Handle>(handle.p); }
static CRequest make(Request request) { return CRequest(request); }
static Request get(CRequest request) { return static_cast<Request>(request.p); }

此处,CHandleCRequest具有链接,因此可以在您的方法签名中使用; makeget的重载具有内部链接,因此可以与匿名类型进行交互。您可以将其放在标题中,甚至是static函数。

您必须修改代码,以便在例如MyCls::myFct调用库,使用get包装参数并使用make返回值。

答案 3 :(得分:0)

这似乎有效:

class MyCls {
  public:
    typedef _Opaque MHandle;
    static void* myFct(MHandle handle) {
      return 0;
    }   
};