定义宏的内容的宏

时间:2011-09-24 18:46:33

标签: c macros

是否可以从宏的内容定义宏?

例如:

#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);
}

经过预处理。

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

5 个答案:

答案 0 :(得分:5)

不,无法在另一个宏中定义宏。

答案 1 :(得分:2)

预处理器仅在编译器之前迭代一次。您所建议的内容需要不确定的迭代次数。

答案 2 :(得分:1)

不,你不能 - 在宏的替换列表中的#表示QUOTE NEXT TOKEN。它比拼写问题更重要,而不是任何逻辑难题:)​​

(如果你的代码需要这种解决方案,那么使用宏的方法和技巧,但你需要具体说明你需要的用例 - 你的例子可以通过定义来实现:#define mykey “值”)

这是来自ansi C99标准

  

6.10.3.2 #erler

     

约束

     

1替换列表中的每个#preprocessing令牌   类似函数的宏后面跟一个参数作为下一个参数   替换列表中的预处理令牌。语义2如果,在   替换列表,参数前面紧跟#   预处理令牌,都被单个字符串替换   包含拼写的文字预处理标记   预处理相应参数的标记序列。每   参数的预处理标记之间出现空白   成为字符串文字中的单个空格字符。   第一个预处理令牌之前和之后的空格   组成参数的预处理标记被删除。否则,   参数中每个预处理标记的原始拼写是   保留在字符串文字中,但特殊处理除外   用于生成字符串文字和字符常量的拼写:   在字符的每个“和\”字符之前插入一个\字符   常量或字符串文字(包括分隔“字符”),   除了它是实现定义是否是\字符   插入\字符开头的通用字符名称。   如果替换结果不是有效的字符串   字面意思,行为是未定义的。字符串文字   对应于空参数是“”。 #的评价顺序   和##运算符未指定。

答案 3 :(得分:0)

宏是一种简单的文本替换。从宏生成新的预处理程序指令需要预处理程序从替换的开始继续预处理。但是,标准定义了预处理以继续落后替换。

从流式传输的角度来看,将未处理的代码视为输入流,将处理后的(和替换的)代码视为输出流,这是有意义的。宏替换可以具有任意长度,这意味着从一开始就预处理必须在输入流的开头插入任意数量的字符以便再次处理。

当处理继续替换后,输入只需在一次运行中处理,无需任何插入或缓冲,因为所有内容都直接进入输出。

答案 4 :(得分:0)

虽然不可能使用宏来定义另一个宏,但是根据你想要实现的目标,你可以使用宏来定义常量来有效地实现同样的事情。例如,我有一个广泛的c宏库,用于定义目标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),然后使用它来调用执行实际定义过程的宏。即,对于列表中的每个项目,传入的宏名称用于定义上下文(“标题”或“实现”,例如“h”或“m”文件,如果您了解目标c文件扩展名)虽然这用于目标c,但它只是普通的旧c宏,用于比可能Kernighan and Richie设想的“更高目的”。 :-)