如何制作一个可以带字符串的宏?

时间:2009-11-25 00:15:27

标签: objective-c cocoa cocoa-touch macros

我正在尝试做一些非常简单的事情:一个接受字符串并将其打印到NSLog的宏。

像这样:

#define PRINTTHIS(text) \
    NSLog(@"text");

但是,当我尝试将字符串传递给这个人时,我最终会将“文本”打印到控制台。是不是所有变量都替换在宏内的字符串级别?怎么做对了?

8 个答案:

答案 0 :(得分:13)

您需要使用预处理器的'stringizing'运算符#,可能还需要使用'token pasting'运算符'##':

#define STRINGIFY2( x) #x
#define STRINGIFY(x) STRINGIFY2(x)
#define PASTE2( a, b) a##b
#define PASTE( a, b) PASTE2( a, b)

#define PRINTTHIS(text) \
    NSLog(PASTE( @, STRINGIFY(text)));

我不确定Objective-C是否要求'@'在它和开头引号之间没有空格 - 如果允许空格,则删除PASTE()操作。

请注意,您需要STRINGIFY()PASTE()的高位2级间接才能正常使用宏参数。除非你做一些非常不寻常的事情(你不希望扩展宏参数),否则它几乎不会受到伤害,因此以这种方式使用这些运算符是非常标准的。

答案 1 :(得分:9)

这是编写宏的一种方法,它将其参数文本化地粘贴到一个字符串对象中,尽管它让我感到有点粗糙:

#define PRINTTHIS(text) NSLog((NSString *)CFSTR(#text))

它使用字符串化运算符将参数转换为C字符串,然后使用该字符串创建一个CFString,它与NSString一起免费桥接。

答案 2 :(得分:7)

看起来这样也行。

#define PRINTTHIS(text) NSLog(@#text);

刚试过它,似乎工作得很好。

答案 3 :(得分:4)

使用

#define PRINTTHIS(text) \
  do { NSLog(@"%s", #text); } while(0)

这样,文字可以包含%字符,它的'if-proof',半冒号都在正确的位置等等......

然而,就个人而言,我认为直接使用NSLog()会更有意义。

答案 4 :(得分:3)

我认为你遇到的问题是“text”在预处理器中看起来像是一个字符串文字(引号,可能是@符号),所以它不会被替换。只是一个猜测,但这会有效吗?

#define PRINTTHIS(text) \
    NSLog(@"%@", text);

PRINTTHIS(@"string");

您还可以定义一个采用C字符串而不是ObjC字符串的版本:

#define PRINTTHIS_C(text) \
    NSLog(@"%s", text);

PRINTTHIS_C("string");

答案 5 :(得分:1)

我的印象是这就是你的意思,并希望

你想要一个可以带参数的字符串,同时包含其他字符串,类似于stringwithformat函数。

#define ThisMacro(value) @"Hello my name is %@, and I'm a developer", value

然后要使用宏,只需将它添加到完整字符串

的值传递给它
NSLog(ThisMacro(@"Mthokozisi"))

最终结果为@"Hello my name is Mthokozisi, and I'm a developer"

答案 6 :(得分:0)

带上一粒盐...我不是Objective-C开发人员。但是在类似C函数的宏中,出现在字符串文字中的宏参数不会被它们对应的实际参数替换,所以你试图做的替换将不起作用。

这可能有效:

#define PRINTTHIS(text) \
    NSLog(@text);

PRINTTHIS("your message here");

(所以引号被移出宏定义。)

Chuck在评论中指出,在Objective-C中,@被认为是令牌的一部分 在这个结构中。因此可能需要使用令牌粘贴操作符##:

#define PRINTTHIS(text) \
        NSLog(@##text);

答案 7 :(得分:0)

我认为只是小心空间。这应该可以正常工作:

#define PRINTTEXT( msg ) NSLog( (msg) )

另一个例子:

#define TFCheckPoint( msg ) [TestFlight passCheckpoint: (msg) ];