我如何制作一个C宏,其中包含一个由空格分隔的单词列表并将它们分开?
我想要一个宏,比如下面的DECLARE()。
#define EXPAND(xy) /* expand sequence of words separated by space into 2 */
#define DECLARE(xy) DECLARE_2(EXPAND(xy)) /* x and y are separated by a space, each should go to each argument of DECLARE_2 */
#define DECLARE_2(const, type) char *type##_str = #type; const type这样我就能做到:
typedef struct MyStruct { int value; } MyStruct;
DECLARE(const MyStruct) x = { 2 };
print(MyStruct_str); // prints 'MyStruct'发布于 2020-09-24 21:34:55
我如何制作一个C宏,其中包含一个由空格分隔的单词列表并将它们分开?
您不能,至少在任何一般情况下,只有标准C定义的预处理功能才能实现,但宏只能使用它们的参数来执行这些操作:
有一些有趣的事情,你可以用其中的最后一个,结合自动重新扫描宏展开,但他们没有达到你想要的任何一般的方式。
发布于 2021-03-11 05:01:51
使用宏,您可以使它在非常特定的情况下工作:y (最后一个令牌)有一个的期望值列表。
在本例中,我们所期望的最后标记列表将是hello、lovely和world,但您可以为您的目的对它们进行微小的更改和扩展。
#define hello_SEPARATE ,hello
#define lovely_SEPARATE ,lovely
#define world_SEPARATE ,world
#define SEPARATE(xy) xy##_SEPARATE以下是一些示例输出:
SEPARATE(hello world) // hello ,world
SEPARATE(world hello) // world ,hello
SEPARATE(hello lovely) // hello ,lovely
SEPARATE(goodbye lovely) // goodbye ,lovely
SEPARATE(I love you world) // I love you ,world
SEPARATE(hello) // ,hello
SEPARATE(goodbye) // goodbye_SEPARATE
SEPARATE(lovely goodbye) // lovely goodbye_SEPARATE如最后一个示例所示,如果最后一个令牌是意外的,它将不能正常工作。
我们可以通过处理那些在失败时发生的不稳定行为来进一步改进上面的解决方案。
在最后的例子中,您可能注意到在开头添加了逗号(即使只有一个关键字)和结尾的"_SEPARATE“。这是如何粗略地定义宏的结果。
要解决这个问题,我们可以利用以下事实:
,),方法是在变量宏中移动参数(类似于此弗吉尼亚,并在此博客帖子中解释)。##)创建伪if语句.以下是最后的解决方案:
// Boilerplate
#define EXPAND(x) x
#define _GLUE(X,Y) X##Y
#define GLUE(X,Y) _GLUE(X,Y)
#define _ARG_100(_,\
_100,_99,_98,_97,_96,_95,_94,_93,_92,_91,_90,_89,_88,_87,_86,_85,_84,_83,_82,_81, \
_80,_79,_78,_77,_76,_75,_74,_73,_72,_71,_70,_69,_68,_67,_66,_65,_64,_63,_62,_61, \
_60,_59,_58,_57,_56,_55,_54,_53,_52,_51,_50,_49,_48,_47,_46,_45,_44,_43,_42,_41, \
_40,_39,_38,_37,_36,_35,_34,_33,_32,_31,_30,_29,_28,_27,_26,_25,_24,_23,_22,_21, \
_20,_19,_18,_17,_16,_15,_14,_13,_12,_11,_10,_9,_8,_7,_6,_5,_4,_3,_2,X_,...) X_
#define HAS_COMMA(...) EXPAND(_ARG_100(__VA_ARGS__, \
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, \
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, \
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, \
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 ,1, \
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0))
#define _TRIGGER_PARENTHESIS_(...) ,
#define _PASTE5(_0, _1, _2, _3, _4) _0 ## _1 ## _2 ## _3 ## _4
#define _IS_EMPTY_CASE_0001 ,
#define _IS_EMPTY(_0, _1, _2, _3) HAS_COMMA(_PASTE5(_IS_EMPTY_CASE_, _0, _1, _2, _3))
#define IS_EMPTY(...) \
_IS_EMPTY( \
HAS_COMMA(__VA_ARGS__), \
HAS_COMMA(_TRIGGER_PARENTHESIS_ __VA_ARGS__), \
HAS_COMMA(__VA_ARGS__ (/*empty*/)), \
HAS_COMMA(_TRIGGER_PARENTHESIS_ __VA_ARGS__ (/*empty*/)) \
)
// Place where you define your expected last tokens
#define hello_REMOVE
#define lovely_REMOVE
#define world_REMOVE
#define hello_SEPARATE ,hello
#define lovely_SEPARATE ,lovely
#define world_SEPARATE ,world
// SEPARATE Macro
#define _IS_EMPTY_TRIGGERED_0(xy) xy##_SEPARATE
#define _IS_EMPTY_TRIGGERED_1(xy) xy
#define _KEYWORD_TRIGGERED_0(xy) xy
#define _KEYWORD_TRIGGERED_1(xy) GLUE(_IS_EMPTY_TRIGGERED_, IS_EMPTY(xy##_REMOVE))(xy)
#define SEPARATE(xy) GLUE(_KEYWORD_TRIGGERED_, HAS_COMMA(xy##_SEPARATE()))(xy)列举的例子如下:
SEPARATE(hello world) // hello ,world
SEPARATE(world hello) // world ,hello
SEPARATE(hello lovely) // hello ,lovely
SEPARATE(goodbye lovely) // goodbye ,lovely
SEPARATE(I love you world) // I love you ,world
SEPARATE(hello) // hello
SEPARATE(goodbye) // goodbye
SEPARATE(lovely goodbye) // lovely goodbye正如您所注意到的,在失败的情况下宏的行为要好得多:它只是返回您输入的内容。
此行为也可自定义。更改"_IS_EMPTY_TRIGGERED_1“(只有一个关键字检测到的案例)和/或"_KEYWORD_TRIGGERED_0”(没有检测到的关键字)的定义将改变失败情况下的行为。例如,如果要使输出成为错误消息,可以将这些行替换为:
//...
#define _IS_EMPTY_TRIGGERED_1(xy) ERROR_1
#define _KEYWORD_TRIGGERED_0(xy) ERROR_2
//...这将是一个结果:
SEPARATE(hello world) // hello ,world
SEPARATE(world hello) // world ,hello
SEPARATE(hello lovely) // hello ,lovely
SEPARATE(goodbye lovely) // goodbye ,lovely
SEPARATE(I love you world) // I love you ,world
SEPARATE(hello) // ERROR_1
SEPARATE(goodbye) // ERROR_2
SEPARATE(lovely goodbye) // ERROR_2注意:在最终版本中,EXPAND紧跟在HAS_COMMA之后,这是一个额外的扩展步骤,以弥补的不足。
发布于 2020-09-24 21:28:06
C中的宏在预处理器中被替换,所以如果您要编写一个这样做的函数,您可以使用宏进行“糖分语法”,但是宏本身不提供任何功能。关于间距问题,您可以参考这个答案:https://stackoverflow.com/a/50000111/14273548
https://stackoverflow.com/questions/64054576
复制相似问题