根据宏的内容定义一个宏

7

能否根据宏的内容定义一个新宏?

举个例子:

#define SET(key,value) #define key value

SET(myKey,"value")

int main(){
   char str[] = myKey;
   printf("%s",str);
}

会导致
int main(){
   char str[] = "value";
   printf("%s",str);
}

在进行预处理之后。

为什么要这样做?因为我很好奇 ;)


编辑你的代码片段,使其有编译的机会,并尝试进行编译。会发生什么呢?我也很好奇。 - Pete Wilson
2
@PeteWilson 尝试编译上述代码时,我收到了“错误:'#'后面没有宏参数”的错误提示。 - Linsey
+1 是为了“我为什么要这样做?”而加的 :) - R.. GitHub STOP HELPING ICE
5个回答

5
不,不可能在另一个宏中定义宏。

2
预处理器只在编译器之前迭代一次。你提出的建议需要进行不确定数量的迭代。

预处理器不仅仅一次确定宏。预处理器允许您多次使用 #undef 和 #define 宏。它在整个处理过程中更改和编辑宏,没有任何东西可以阻止它在宏内部编辑这些规则。 - Linsey
预处理器所做的是“遍历所有文件并按某种顺序替换一些字符串”。有一个顺序使它具有记忆和 #undef #ifdef 等功能... 但是,要将替换后的字符串作为宏获取需要使用递归。 - Willy
请提供一个例子。我同意如果您想替换内部#define之前的文本,则需要使用递归,但是如果代码从那一点开始生效,则似乎没有问题。 - Linsey
我不明白你想要什么样的例子,但这对我来说很简单:如果这是标准支持的,那么它应该递归;或者如果它不被支持,那么它就不会——因为在宏定义中不允许使用 #,这似乎就是情况。 - Willy
1
一个例子会帮助我理解为什么嵌套的#define不能被实现在标准中。看起来并没有递归问题,你能提供一个需要递归的C代码示例吗? - Linsey

1

不行 - 在宏的替换列表中,#表示引用下一个标记。这更像是一个拼写问题,而不是逻辑难题 :)

(如果您需要在代码中使用此类解决方案,则有使用宏的方法和技巧,但您需要具体说明所需的用例 - 因为您的示例可以通过定义实现:#define mykey“value”)

这是来自ANSI C99标准的内容。

6.10.3.2 #运算符 限制条件 1.函数宏替换列表中每个#预处理标记后面必须跟随一个参数作为替换列表中的下一个预处理标记。 2.如果在替换列表中,一个参数紧接着被#预处理符号,则两者都被替换为一个单字符字符串字面量预处理标记,其中包含相应参数的预处理标记序列的拼写。在参数的预处理标记之间出现的任何空格都会在字符字符串字面量中变成一个空格字符。组成参数的第一个预处理标记之前和最后一个预处理标记之后的空格将被删除。否则,在字符字符串字面量中,保留参数中每个预处理标记的原始拼写,除了用于生成字符串字面量和字符常量拼写的特殊处理:在字符常量或字符串字面量(包括定界“字符)的每个"和\字符之前插入一个\字符,但是在普通字符名称之前开始的\字符是否插入一个\字符是由实现定义的。如果结果替换不是有效的字符字符串字面量,则行为是未定义的。对应于空参数的字符字符串字面量为""。#和##操作符的评估顺序是未指定的。

0

虽然不可能使用宏定义另一个宏,但根据你想要实现的目标,你可以使用宏将它们定义为常量以有效地实现相同的功能。例如,我有一个广泛的 C 宏库,用于定义 Objective C 的常量字符串和键值。

以下是我的某些头文件中的代码片段。

// use defineStringsIn_X_File to define a NSString constant to a literal value.
// usage (direct)   : defineStringsIn_X_File(constname,value);

#define defineStringsIn_h_File(constname,value)   extern NSString * const constname; 
#define defineStringsIn_m_File(constname,value)   NSString * const constname = value; 


// use defineKeysIn_X_File when the value is the same as the key. 
// eg myKeyname has the value @"myKeyname"
// usage (direct)   : defineKeysIn_X_File(keyname);
// usage (indirect) : myKeyDefiner(defineKeysIn_X_File);
#define defineKeysIn_h_File(key)  defineStringsIn_h_File(key,key) 
#define defineKeysIn_m_File(key)  defineStringsIn_m_File(key,@#key) 



// use defineKeyValuesIn_X_File when the value is completely unrelated to the key - ie you supply a quoted value.
// eg myKeyname has the value @"keyvalue"
// usage: defineKeyValuesIn_X_File(keyname,@"keyvalue");
// usage (indirect) : myKeyDefiner(defineKeyValuesIn_X_File);
#define defineKeyValuesIn_h_File(key,value)   defineStringsIn_h_File(key,value)  
#define defineKeyValuesIn_m_File(key,value)   defineStringsIn_m_File(key,value) 



// use definePrefixedKeys_in_X_File when the last part of the keyname is the same as the value.
// eg myPrefixed_keyname has the value @"keyname"
// usage (direct)   : definePrefixedKeys_in_X_File(prefix_,keyname);
// usage (indirect) : myKeyDefiner(definePrefixedKeys_in_X_File);

#define definePrefixedKeys_in_h_File_2(prefix,key) defineKeyValuesIn_h_File(prefix##key,@#key) 
#define definePrefixedKeys_in_m_File_2(prefix,key) defineKeyValuesIn_m_File(prefix##key,@#key) 

#define definePrefixedKeys_in_h_File_3(prefix,key,NSObject) definePrefixedKeys_in_h_File_2(prefix,key)
#define definePrefixedKeys_in_m_File_3(prefix,key,NSObject) definePrefixedKeys_in_m_File_2(prefix,key)

#define definePrefixedKeys_in_h_File(...) VARARG(definePrefixedKeys_in_h_File_, __VA_ARGS__)
#define definePrefixedKeys_in_m_File(...) VARARG(definePrefixedKeys_in_m_File_, __VA_ARGS__)




// use definePrefixedKeyValues_in_X_File when the value has no relation to the keyname, but the keyname has a common prefixe
// eg myPrefixed_keyname has the value @"bollocks"
// usage: definePrefixedKeyValues_in_X_File(prefix_,keyname,@"bollocks");
// usage (indirect) : myKeyDefiner(definePrefixedKeyValues_in_X_File);
#define definePrefixedKeyValues_in_h_File(prefix,key,value) defineKeyValuesIn_h_File(prefix##key,value) 
#define definePrefixedKeyValues_in_m_File(prefix,key,value) defineKeyValuesIn_m_File(prefix##key,value) 







#define VA_NARGS_IMPL(_1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, N, ...) N
#define VA_NARGS(...) VA_NARGS_IMPL(X,##__VA_ARGS__, 11, 10,9, 8, 7, 6, 5, 4, 3, 2, 1, 0)
#define VARARG_IMPL2(base, count, ...) base##count(__VA_ARGS__)
#define VARARG_IMPL(base, count, ...) VARARG_IMPL2(base, count, __VA_ARGS__) 
#define VARARG(base, ...) VARARG_IMPL(base, VA_NARGS(__VA_ARGS__), __VA_ARGS__)

以及调用它的使用示例:

#define sw_Logging_defineKeys(defineKeyValue) \
/** start of key list for sw_Logging_ **/\
/**/defineKeyValue(sw_Logging_,log)\
/**/defineKeyValue(sw_Logging_,time)\
/**/defineKeyValue(sw_Logging_,message)\
/**/defineKeyValue(sw_Logging_,object)\
/**/defineKeyValue(sw_Logging_,findCallStack)\
/**/defineKeyValue(sw_Logging_,debugging)\
/**/defineKeyValue(sw_Logging_,callStackSymbols)\
/**/defineKeyValue(sw_Logging_,callStackReturnAddresses)\
/** end of key list for sw_Logging_ **/
sw_Logging_defineKeys(definePrefixedKeys_in_h_File);

最后一部分可能有点难以理解。 sw_Logging_defineKeys()宏定义了一个列表,该列表以宏的名称作为其参数(defineKeyValue),然后用于调用执行实际定义过程的宏。即,对于列表中的每个项目,传递的宏名称用于定义上下文(“头文件”或“实现文件”,例如,如果您了解Objective-C文件扩展名,则为“h”或“m”文件)。虽然这用于Objective-C,但它只是普通的C宏,用于比可能Kernighan and Richie曾经设想的更高目的。 :-)


0

宏是一种简单的文本替换。从宏生成新的预处理指令需要预处理器从替换的开头继续预处理。然而,标准定义了预处理应该在替换后面继续。

从流的角度来看,这是有道理的,将未处理的代码视为输入流,处理(和替换)的代码视为输出流。宏替换可以具有任意长度,这意味着对于从开头进行的预处理,必须在输入流的开头插入任意数量的字符以再次处理。

当处理在替换后继续时,输入只需在一个单独的运行中处理,无需插入或缓冲,因为所有内容直接进入输出。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接