首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >C宏将单个令牌拆分为两个

C宏将单个令牌拆分为两个
EN

Stack Overflow用户
提问于 2020-09-24 21:20:16
回答 3查看 580关注 0票数 1

我如何制作一个C宏,其中包含一个由空格分隔的单词列表并将它们分开?

我想要一个宏,比如下面的DECLARE()。

代码语言:javascript
复制
#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

这样我就能做到:

代码语言:javascript
复制
typedef struct MyStruct { int value; } MyStruct;
DECLARE(const MyStruct) x = { 2 };
print(MyStruct_str); // prints 'MyStruct'
EN

回答 3

Stack Overflow用户

回答已采纳

发布于 2020-09-24 21:34:55

我如何制作一个C宏,其中包含一个由空格分隔的单词列表并将它们分开?

您不能,至少在任何一般情况下,只有标准C定义的预处理功能才能实现,但宏只能使用它们的参数来执行这些操作:

  • 将它们全部插入到其他令牌序列中(包括将它们作为参数间接传递给其他宏)
  • 将它们转换为字符串
  • 将第一个和/或最后一个令牌与其他令牌连接起来

有一些有趣的事情,你可以用其中的最后一个,结合自动重新扫描宏展开,但他们没有达到你想要的任何一般的方式。

票数 3
EN

Stack Overflow用户

发布于 2021-03-11 05:01:51

使用宏,您可以使它在非常特定的情况下工作:y (最后一个令牌)有一个的期望值列表。

在本例中,我们所期望的最后标记列表将是hellolovelyworld,但您可以为您的目的对它们进行微小的更改和扩展。

代码语言:javascript
复制
#define hello_SEPARATE ,hello
#define lovely_SEPARATE ,lovely
#define world_SEPARATE ,world

#define SEPARATE(xy) xy##_SEPARATE

以下是一些示例输出:

代码语言:javascript
复制
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“。这是如何粗略地定义宏的结果。

要解决这个问题,我们可以利用以下事实:

  1. C预处理器只有在后面加上括号时才会触发类似函数的宏。
  2. 我们可以在可变宏参数中检测逗号(,),方法是在变量宏中移动参数(类似于此弗吉尼亚,并在此博客帖子中解释)。
  3. 我们可以使用fact 2和令牌连接(##)创建伪if语句.
  4. 我们可以使用1、2和3来检测变量宏是否没有参数(如Jens在这个博客帖子中所解释的)。

以下是最后的解决方案:

代码语言:javascript
复制
// 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)

列举的例子如下:

代码语言:javascript
复制
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”(没有检测到的关键字)的定义将改变失败情况下的行为。例如,如果要使输出成为错误消息,可以将这些行替换为:

代码语言:javascript
复制
//...
#define _IS_EMPTY_TRIGGERED_1(xy) ERROR_1

#define _KEYWORD_TRIGGERED_0(xy) ERROR_2
//...

这将是一个结果:

代码语言:javascript
复制
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之后,这是一个额外的扩展步骤,以弥补的不足。

票数 3
EN

Stack Overflow用户

发布于 2020-09-24 21:28:06

C中的宏在预处理器中被替换,所以如果您要编写一个这样做的函数,您可以使用宏进行“糖分语法”,但是宏本身不提供任何功能。关于间距问题,您可以参考这个答案:https://stackoverflow.com/a/50000111/14273548

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/64054576

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档