定义时宏扩展中的 GObject 编译错误 Class
GObject Compilation Error in Macro Expansion While Defining Class
问题
使用 GObject 和 C,我试图在模块“Foo”中创建名为“Bar”的 class GObject 的子class。但是,宏“G_DECLARE_FINAL_TYPE”(在 gobject/gtype.h 中定义)扩展不正确。它没有扩展到 FOO_BAR,而是什么都没有。所以不是扩展到:
... FooBar * FOO_BAR (gpointer ptr) { ...
而是扩展为:
... FooBar * (gpointer ptr) { ...
错误信息
我希望它能编译,但 gcc 给出了语法错误:
In file included from /usr/include/glib-2.0/gobject/gobject.h:24,
from /usr/include/glib-2.0/gobject/gbinding.h:29,
from /usr/include/glib-2.0/glib-object.h:22,
from foo-bar.h:4,
from foo-bar.c:1:
/usr/include/glib-2.0/gobject/gtype.h:1407:77: error: expected ‘)’ before ‘ptr’
1407 | USED static inline ModuleObjName * MODULE##_##OBJ_NAME (gpointer ptr) { \
| ^~~
foo-bar.h:10:1: note: in expansion of macro ‘G_DECLARE_FINAL_TYPE’
10 | G_DECLARE_FINAL_TYPE (FooBar, foo_bar, FOO, BAR, GObject)
| ^~~~~~~~~~~~~~~~~~~~
宏定义
此定义来自 glib 2.66.7 库。我没有自己定义它。为了完整起见,我将其包括在内。
#define G_DECLARE_FINAL_TYPE(ModuleObjName, module_obj_name, MODULE, OBJ_NAME, ParentName) \
GType module_obj_name##_get_type (void); \
G_GNUC_BEGIN_IGNORE_DEPRECATIONS \
typedef struct _##ModuleObjName ModuleObjName; \
typedef struct { ParentName##Class parent_class; } ModuleObjName##Class; \
\
_GLIB_DEFINE_AUTOPTR_CHAINUP (ModuleObjName, ParentName) \
G_DEFINE_AUTOPTR_CLEANUP_FUNC (ModuleObjName##Class, g_type_class_unref) \
\
G_GNUC_UNUSED static inline ModuleObjName * MODULE##_##OBJ_NAME (gpointer ptr) { \
return G_TYPE_CHECK_INSTANCE_CAST (ptr, module_obj_name##_get_type (), ModuleObjName); }\
G_GNUC_UNUSED static inline gboolean MODULE##_IS_##OBJ_NAME (gpointer ptr) { \
return G_TYPE_CHECK_INSTANCE_TYPE (ptr, module_obj_name##_get_type ()); } \
G_GNUC_END_IGNORE_DEPRECATIONS
部分预处理器输出
我包含了包含语法错误的定义并对其进行了格式化以便于阅读:
__attribute__((__unused__)) static inline FooBar * (gpointer ptr) {
return (((FooBar*) g_type_check_instance_cast ((GTypeInstance*) (ptr), (foo_bar_get_type ()))));
}
奇怪的是下面的定义确实得到了正确的预处理:
__attribute__((__unused__)) static inline gboolean FOO_IS_BAR (gpointer ptr) {
return ((__extension__ ({
GTypeInstance *__inst = (GTypeInstance*) (ptr);
GType __t = (foo_bar_get_type ());
gboolean __r;
if (!__inst) __r = (0);
else if (__inst->g_class && __inst->g_class->g_type == __t) __r = (!(0));
else __r = g_type_check_instance_is_a (__inst, __t); __r; })));
}
完整的最小示例
我在下面包含了一个导致我的错误的最小示例。
foo-bar.h
#ifndef FOO_BAR
#define FOO_BAR
#include <glib-object.h>
G_BEGIN_DECLS
#define FOO_TYPE_BAR (foo_bar_get_type ())
G_DECLARE_FINAL_TYPE (FooBar, foo_bar, FOO, BAR, GObject)
G_END_DECLS
#endif /* FOO_BAR */
foo-bar.c
#include "foo-bar.h"
struct _FooBar
{
GObject parent_instance;
};
G_DEFINE_TYPE (FooBar, foo_bar, G_TYPE_OBJECT);
static void foo_bar_class_init (FooBarClass *klass)
{
}
static void foo_bar_init (FooBar *app)
{
}
生成文件
foo-bar.o: foo-bar.c
gcc -c foo-bar.c $(shell pkg-config --cflags gobject-2.0) -o foo-bar.o
# included to debug the macro
foo-bar.pp: foo-bar.c
gcc -E foo-bar.c $(shell pkg-config --cflags gobject-2.0) -o foo-bar.pp
版本
- glib 2.66.7
- gcc 10.2.1
- Linux(软呢帽 33)
我试过的
我研究了glib's documentation on how to create a new class and as far as I can tell I am doing it correctly. I have also looked up how token pasting and macro expansion work, and also tried googling my error. It must be something obvious, but I cannot figure out what. I also tried declaring a derivable class with private data, but while finding a minimal example I changed it to a final class without private data and still have the same error. I read about the ## operator here,还是说不出哪里不对。
相关堆栈溢出问题
最后看了下相关的Whosebugposts:
我的错误是预处理器没有发出连接的标记。在 post 中,用户定义了自己的宏并询问为什么一个调用有效而另一个无效。我使用的是库而不是我自己的宏。
This 问题是询问为什么宏在 unicode 模式和 ascii 模式下的扩展方式不同。我不处理 unicode,所以它不相关。
我没有使用 C++,只使用没有泛型语法的 C,所以 问题不适用于我。
由于我没有使用 XCode this 问题没有解决我的问题。
我了解宏扩展应该如何工作,所以 this 这个问题确实告诉了我任何我还不知道的事情。
我没有定义任何新宏,也没有命名空间冲突问题,这与 this 问题不同。
在 this and 问题中,用户不知道宏中的连接运算符。我是,我的问题是它也没有像我期望的那样工作。所以说运算符存在对我没有帮助。
,但它的发生是因为没有提供宏的参数。我提供了所有论据,所以它对我没有帮助。
This question the user is using the pasting operator when they don't need to.。在我的例子中,粘贴运算符是必要的。
好吧,这很愚蠢。发布这个以防有人遇到这个答案。
问题是我的 include guard。它应该是 FOO_BAR_H 因为文件的名称是 foo-bar.h。但是,它被定义为FOO_BAR。当 gobject 生成标记“FOO_BAR”时,预处理器意识到它是一个已经定义的宏,但在这种情况下定义是空的。然而,它用它的定义替换了宏。
解决方案是在包含防护中将“FOO_BAR”替换为“FOO_BAR_H”。
问题
使用 GObject 和 C,我试图在模块“Foo”中创建名为“Bar”的 class GObject 的子class。但是,宏“G_DECLARE_FINAL_TYPE”(在 gobject/gtype.h 中定义)扩展不正确。它没有扩展到 FOO_BAR,而是什么都没有。所以不是扩展到:
... FooBar * FOO_BAR (gpointer ptr) { ...
而是扩展为:
... FooBar * (gpointer ptr) { ...
错误信息
我希望它能编译,但 gcc 给出了语法错误:
In file included from /usr/include/glib-2.0/gobject/gobject.h:24,
from /usr/include/glib-2.0/gobject/gbinding.h:29,
from /usr/include/glib-2.0/glib-object.h:22,
from foo-bar.h:4,
from foo-bar.c:1:
/usr/include/glib-2.0/gobject/gtype.h:1407:77: error: expected ‘)’ before ‘ptr’
1407 | USED static inline ModuleObjName * MODULE##_##OBJ_NAME (gpointer ptr) { \
| ^~~
foo-bar.h:10:1: note: in expansion of macro ‘G_DECLARE_FINAL_TYPE’
10 | G_DECLARE_FINAL_TYPE (FooBar, foo_bar, FOO, BAR, GObject)
| ^~~~~~~~~~~~~~~~~~~~
宏定义
此定义来自 glib 2.66.7 库。我没有自己定义它。为了完整起见,我将其包括在内。
#define G_DECLARE_FINAL_TYPE(ModuleObjName, module_obj_name, MODULE, OBJ_NAME, ParentName) \
GType module_obj_name##_get_type (void); \
G_GNUC_BEGIN_IGNORE_DEPRECATIONS \
typedef struct _##ModuleObjName ModuleObjName; \
typedef struct { ParentName##Class parent_class; } ModuleObjName##Class; \
\
_GLIB_DEFINE_AUTOPTR_CHAINUP (ModuleObjName, ParentName) \
G_DEFINE_AUTOPTR_CLEANUP_FUNC (ModuleObjName##Class, g_type_class_unref) \
\
G_GNUC_UNUSED static inline ModuleObjName * MODULE##_##OBJ_NAME (gpointer ptr) { \
return G_TYPE_CHECK_INSTANCE_CAST (ptr, module_obj_name##_get_type (), ModuleObjName); }\
G_GNUC_UNUSED static inline gboolean MODULE##_IS_##OBJ_NAME (gpointer ptr) { \
return G_TYPE_CHECK_INSTANCE_TYPE (ptr, module_obj_name##_get_type ()); } \
G_GNUC_END_IGNORE_DEPRECATIONS
部分预处理器输出
我包含了包含语法错误的定义并对其进行了格式化以便于阅读:
__attribute__((__unused__)) static inline FooBar * (gpointer ptr) {
return (((FooBar*) g_type_check_instance_cast ((GTypeInstance*) (ptr), (foo_bar_get_type ()))));
}
奇怪的是下面的定义确实得到了正确的预处理:
__attribute__((__unused__)) static inline gboolean FOO_IS_BAR (gpointer ptr) {
return ((__extension__ ({
GTypeInstance *__inst = (GTypeInstance*) (ptr);
GType __t = (foo_bar_get_type ());
gboolean __r;
if (!__inst) __r = (0);
else if (__inst->g_class && __inst->g_class->g_type == __t) __r = (!(0));
else __r = g_type_check_instance_is_a (__inst, __t); __r; })));
}
完整的最小示例
我在下面包含了一个导致我的错误的最小示例。
foo-bar.h
#ifndef FOO_BAR
#define FOO_BAR
#include <glib-object.h>
G_BEGIN_DECLS
#define FOO_TYPE_BAR (foo_bar_get_type ())
G_DECLARE_FINAL_TYPE (FooBar, foo_bar, FOO, BAR, GObject)
G_END_DECLS
#endif /* FOO_BAR */
foo-bar.c
#include "foo-bar.h"
struct _FooBar
{
GObject parent_instance;
};
G_DEFINE_TYPE (FooBar, foo_bar, G_TYPE_OBJECT);
static void foo_bar_class_init (FooBarClass *klass)
{
}
static void foo_bar_init (FooBar *app)
{
}
生成文件
foo-bar.o: foo-bar.c
gcc -c foo-bar.c $(shell pkg-config --cflags gobject-2.0) -o foo-bar.o
# included to debug the macro
foo-bar.pp: foo-bar.c
gcc -E foo-bar.c $(shell pkg-config --cflags gobject-2.0) -o foo-bar.pp
版本
- glib 2.66.7
- gcc 10.2.1
- Linux(软呢帽 33)
我试过的
我研究了glib's documentation on how to create a new class and as far as I can tell I am doing it correctly. I have also looked up how token pasting and macro expansion work, and also tried googling my error. It must be something obvious, but I cannot figure out what. I also tried declaring a derivable class with private data, but while finding a minimal example I changed it to a final class without private data and still have the same error. I read about the ## operator here,还是说不出哪里不对。
相关堆栈溢出问题
最后看了下相关的Whosebugposts:
我的错误是预处理器没有发出连接的标记。在
This 问题是询问为什么宏在 unicode 模式和 ascii 模式下的扩展方式不同。我不处理 unicode,所以它不相关。
我没有使用 C++,只使用没有泛型语法的 C,所以
由于我没有使用 XCode this 问题没有解决我的问题。
我了解宏扩展应该如何工作,所以 this 这个问题确实告诉了我任何我还不知道的事情。
我没有定义任何新宏,也没有命名空间冲突问题,这与 this 问题不同。
在 this and
This question the user is using the pasting operator when they don't need to.。在我的例子中,粘贴运算符是必要的。
好吧,这很愚蠢。发布这个以防有人遇到这个答案。
问题是我的 include guard。它应该是 FOO_BAR_H 因为文件的名称是 foo-bar.h。但是,它被定义为FOO_BAR。当 gobject 生成标记“FOO_BAR”时,预处理器意识到它是一个已经定义的宏,但在这种情况下定义是空的。然而,它用它的定义替换了宏。
解决方案是在包含防护中将“FOO_BAR”替换为“FOO_BAR_H”。