6

我们有一个大型的、旧的 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

4 回答 4

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最小的联系。

于 2012-08-13T13:19:12.110 回答
1

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

namespace MON {
struct t_handle {
  Handle handle;
};

class MyCls {
public:
    static void* myFct(t_handle handle);
    ...
};
}
于 2012-08-13T12:08:24.120 回答
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有链接等可以在你的方法签名中使用;make和的重载get具有内部链接,因此可以与匿名类型交互。你可以把它放在一个标题中,甚至是static函数。

您必须修改您的代码,以便在MyCls::myFct调用库时,您可以使用 包装参数get并使用make.

于 2012-08-13T13:47:40.813 回答
0

这似乎有效:

class MyCls {
  public:
    typedef _Opaque MHandle;
    static void* myFct(MHandle handle) {
      return 0;
    }   
};
于 2012-08-13T12:10:30.140 回答