C API中的问题

你可能会在封装库的过程中遇到一些问题。特别是它是一个新项目的时候。以下是一些常见问题以及解决方案。

G.6.1. 无法提前声明的结构体

按照约定,glib/GTK风格的头文件中结构体声明应如下所示:

typedef struct _ExampleWidget ExampleWidget;

struct _ExampleWidget
{
  ...
};

额外的typedef允许在头文件中使用该结构体而不需要包含其完整定义,只需要通过重复这个typedef预先声明它即可。这意味着你不需要在你的C++头文件中包含C库的头文件。,从而将其排除在你的公共API之外。gmmproc假定使用了这个技术,因此如果没使用这种技术就会遇到编译错误。

编译错误看起来可能如下所示:

example-widget.h:56: error: using typedef-name 'ExampleWidget' after 'struct'
../../libexample/libexamplemm/example-widget.h:34: error: 'ExampleWidget' has a previous declaration here
make[4]: *** [example-widget.lo] Error 1
或如下所示:
example-widget.h:60: error: '_ExampleWidget ExampleWidget' redeclared as different kind of symbol
../../libexample/libexamplemm/example-widget.h:34: error: previous declaration of 'typedef struct _ExampleWidget ExampleWidget'

这很容易在C库中修复,你可以向相关库的维护者发送补丁。

G.6.2. 缺少属性

按照约定,glib/GTK风格对象应具有*_new()函数,例如example_widget_new()仅调用g_object_new()并返回其结果。输入参数为g_object_new()函数提供属性名和属性值。例如:

GtkWidget* example_widget_new(int something, const char* thing)
{
        return g_object_new (EXAMPLE_TYPE_WIDGET, "something", something, "thing", thing, NULL);
}

这允许语言绑定实现自己的等效项(例如C++构造函数),而不需要使用*_new()函数。这通常是必须的,这是为了让它们可以实例化派生的GType,这样就可以为信号处理函数和虚函数添加自己的钩子。

_new()函数不应该使用任何只在.c文件中的私有API。即使没有对应的函数,有时我们也可以在_new()函数中重新实现2到3行代码,只要这些行使用的API是可用的。

另一个解决方法是添加一个C++构造函数可以在实例化自身类型后调用的*_construct()函数。例如:

GtkWidget* example_widget_new(int something, const char* thing)
{
        ExampleWidget* widget;
        widget = g_object_new (EXAMPLE_TYPE_WIDGET, NULL);
        example_widget_construct(widget, "something", something, "thing", thing);
}

void example_widget_construct(ExampleWidget* widget, int something, const char* thing)
{
        //Do stuff that uses private API:
        widget->priv->thing = thing;
        do_something(something);
}

在C库中,添加属性并确保它们之间正确的进行交互相对来说比较困难。但还是能做到的。若你发现了一个bug请联系相关的维护人员并向其提供相关信息以便尽快修复该bug。