C 如何在宏中使用宏来转换宏';谁的论点?
我在我的项目中使用,以便在名称列表都需要对其执行相同操作(例如创建、初始化、填充和销毁)的地方使用 由于我曾经试图指定的数据涉及一些相同的可宏转换(忽略参数、前缀和后缀),因此我决定将它们重写为广义元X-宏,从中可以定义多个派生的最终用例拟合X-宏,以增强性能,使用解释元宏参数的转换宏:C 如何在宏中使用宏来转换宏';谁的论点?,c,macros,c-preprocessor,C,Macros,C Preprocessor,我在我的项目中使用,以便在名称列表都需要对其执行相同操作(例如创建、初始化、填充和销毁)的地方使用 由于我曾经试图指定的数据涉及一些相同的可宏转换(忽略参数、前缀和后缀),因此我决定将它们重写为广义元X-宏,从中可以定义多个派生的最终用例拟合X-宏,以增强性能,使用解释元宏参数的转换宏: // Meta-macros // #define MAIN_WINDOW_TEXT_LAYERS_METAMACRO(macro, tr) \ macro(tr(hour_layer)) \ mac
// Meta-macros //
#define MAIN_WINDOW_TEXT_LAYERS_METAMACRO(macro, tr) \
macro(tr(hour_layer)) \
macro(tr(min_layer)) \
macro(tr(date_layer))
#define MAIN_WINDOW_LAYERS_METAMACRO(macro, tr) \
macro(tr(colon_layer)) \
macro(tr(phone_batt_layer)) \
macro(tr(watch_batt_layer))
#define GBITMAPS_WITH_RESOURCE_IDS_METAMACRO(macro, tr) \
macro(tr(watch_icon, ICON_WATCH_6X11)) \
macro(tr(watch_charging_icon, ICON_WATCH_CHARGING_6X11)) \
macro(tr(phone_icon, ICON_PHONE_6X11)) \
macro(tr(phone_charging_icon, ICON_PHONE_CHARGING_6X11))
#define GFONTS_WITH_RESOURCE_IDS_METAMACRO(macro, tr) \
macro(tr(time_font, FONT_ARVO_BOLD_48)) \
macro(tr(date_font, FONT_ARVO_BOLD_20))
// Transformation macros //
#define IDENTITY_MACRO(x) x
#define STATIC_PREFIX_MACRO(x) s_ ## x
#define STATIC_PREFIX_DISCARD_MACRO(x, _) s_ ## x
#define STATIC_PREFIX_RESOURCE_ID_PREFIX_MACRO(x, id) \
s_ ## x, RESOURCE_ID_ ## s
// Derived X-Macros //
#define FOR_MAIN_WINDOW_STATIC_TEXT_LAYER_POINTERS(macro) \
MAIN_WINDOW_TEXT_LAYERS_METAMACRO(macro, STATIC_PREFIX_MACRO)
#define FOR_MAIN_WINDOW_STATIC_LAYER_POINTERS(macro) \
MAIN_WINDOW_LAYERS_METAMACRO(macro, STATIC_PREFIX_MACRO)
#define FOR_MAIN_WINDOW_LAYER_NAMES(macro) \
MAIN_WINDOW_LAYERS_METAMACRO(macro, IDENTITY_MACRO)
#define FOR_STATIC_GFONTS(macro) \
GFONTS_WITH_RESOURCE_IDS_METAMACRO(macro, STATIC_PREFIX_DISCARD_MACRO)
#define FOR_STATIC_GFONTS_WITH_RESOURCE_IDS(macro) \
GFONTS_WITH_RESOURCE_IDS_METAMACRO(macro, STATIC_PREFIX_RESOURCE_ID_PREFIX_MACRO)
#define FOR_STATIC_GBITMAP_POINTERS_WITH_RESOURCE_IDS(macro) \
GBITMAPS_WITH_RESOURCE_IDS_METAMACRO(macro, STATIC_PREFIX_RESOURCE_ID_PREFIX_MACRO)
#define FOR_STATIC_GBITMAP_POINTERS(macro) \
GBITMAPS_WITH_RESOURCE_IDS_METAMACRO(macro, STATIC_PREFIX_DISCARD_MACRO)
#define X_(name, id) name = fonts_load_custom_font(resource_get_handle(id));
#define X(args) X_(args)
FOR_STATIC_GFONTS_WITH_RESOURCE_IDS(X)
#undef X
#undef X_
这在大多数用例中都是有效的:然而,在一些边缘情况下,我遇到了麻烦。首先,尝试连接参数会导致连接转换宏的名称,而不是转换后的名称:
其次,转换两个参数的宏没有得到扩展-它们被作为单个标记传递给X
(对转换宏的调用):
如何使它们按我希望的方式工作?正如在关于C预处理器的文章中所提到的,可以通过向宏引入另一层间接求值来避免第一个问题(宏的标识符被连接而不是其内容):
#define X_(name) layer_set_update_proc(s_ ## name, name ## _update_proc);
#define X(name) X_(name)
FOR_MAIN_WINDOW_LAYER_NAMES(X)
#undef X
#undef X_
第二个问题更阴险,但它有一个类似的解决方案:另一个间接层。这里的关键技巧是,第一层必须采用一个单参数传递到下一层,然后扩展到多个参数,而不是复制最后一个宏的签名:
// Meta-macros //
#define MAIN_WINDOW_TEXT_LAYERS_METAMACRO(macro, tr) \
macro(tr(hour_layer)) \
macro(tr(min_layer)) \
macro(tr(date_layer))
#define MAIN_WINDOW_LAYERS_METAMACRO(macro, tr) \
macro(tr(colon_layer)) \
macro(tr(phone_batt_layer)) \
macro(tr(watch_batt_layer))
#define GBITMAPS_WITH_RESOURCE_IDS_METAMACRO(macro, tr) \
macro(tr(watch_icon, ICON_WATCH_6X11)) \
macro(tr(watch_charging_icon, ICON_WATCH_CHARGING_6X11)) \
macro(tr(phone_icon, ICON_PHONE_6X11)) \
macro(tr(phone_charging_icon, ICON_PHONE_CHARGING_6X11))
#define GFONTS_WITH_RESOURCE_IDS_METAMACRO(macro, tr) \
macro(tr(time_font, FONT_ARVO_BOLD_48)) \
macro(tr(date_font, FONT_ARVO_BOLD_20))
// Transformation macros //
#define IDENTITY_MACRO(x) x
#define STATIC_PREFIX_MACRO(x) s_ ## x
#define STATIC_PREFIX_DISCARD_MACRO(x, _) s_ ## x
#define STATIC_PREFIX_RESOURCE_ID_PREFIX_MACRO(x, id) \
s_ ## x, RESOURCE_ID_ ## s
// Derived X-Macros //
#define FOR_MAIN_WINDOW_STATIC_TEXT_LAYER_POINTERS(macro) \
MAIN_WINDOW_TEXT_LAYERS_METAMACRO(macro, STATIC_PREFIX_MACRO)
#define FOR_MAIN_WINDOW_STATIC_LAYER_POINTERS(macro) \
MAIN_WINDOW_LAYERS_METAMACRO(macro, STATIC_PREFIX_MACRO)
#define FOR_MAIN_WINDOW_LAYER_NAMES(macro) \
MAIN_WINDOW_LAYERS_METAMACRO(macro, IDENTITY_MACRO)
#define FOR_STATIC_GFONTS(macro) \
GFONTS_WITH_RESOURCE_IDS_METAMACRO(macro, STATIC_PREFIX_DISCARD_MACRO)
#define FOR_STATIC_GFONTS_WITH_RESOURCE_IDS(macro) \
GFONTS_WITH_RESOURCE_IDS_METAMACRO(macro, STATIC_PREFIX_RESOURCE_ID_PREFIX_MACRO)
#define FOR_STATIC_GBITMAP_POINTERS_WITH_RESOURCE_IDS(macro) \
GBITMAPS_WITH_RESOURCE_IDS_METAMACRO(macro, STATIC_PREFIX_RESOURCE_ID_PREFIX_MACRO)
#define FOR_STATIC_GBITMAP_POINTERS(macro) \
GBITMAPS_WITH_RESOURCE_IDS_METAMACRO(macro, STATIC_PREFIX_DISCARD_MACRO)
#define X_(name, id) name = fonts_load_custom_font(resource_get_handle(id));
#define X(args) X_(args)
FOR_STATIC_GFONTS_WITH_RESOURCE_IDS(X)
#undef X
#undef X_
当然,将这类变通方法转移到使用点,而不是在定义它们的地方修复它们,这不是健壮的工程,因此应该将这一间接层定义为元宏本身的一部分:
但是,请注意,您选择用于APPLY_MACRO
的任何标记,都不同于X
或X
这样的标识符,它们可以\define
d并立即在调用点附近定义\undef
,这里使用的间接宏必须保持定义状态,只要这些宏本身可以使用(显然),因此应该选择一个不容易与代码库的其他部分(即,不仅仅是X
)发生冲突的名称。即使像apply\u宏
宏
#define X(name, id) name = gbitmap_create_with_resource(id);
FOR_STATIC_GBITMAP_POINTERS_WITH_RESOURCE_IDS(X)
#undef X
error: macro "X" requires 2 arguments, but only 1 given
error: expected '=', ',', ';', 'asm' or '__attribute__' before 'X'
#define X_(name) layer_set_update_proc(s_ ## name, name ## _update_proc);
#define X(name) X_(name)
FOR_MAIN_WINDOW_LAYER_NAMES(X)
#undef X
#undef X_
#define X_(name, id) name = fonts_load_custom_font(resource_get_handle(id));
#define X(args) X_(args)
FOR_STATIC_GFONTS_WITH_RESOURCE_IDS(X)
#undef X
#undef X_
#define APPLY_MACRO(x, t) x(t)
#define MAIN_WINDOW_TEXT_LAYERS_METAMACRO(X, tr) \
APPLY_MACRO(X,tr(hour_layer)) \
APPLY_MACRO(X,tr(min_layer)) \
APPLY_MACRO(X,tr(date_layer))
/* etc... */