为什么我需要宏的双层间接寻址?
在:C++ FAQ - Miscellaneous technical issues - [39.6] What should be done with macros that need to paste two tokens together?为什么我需要宏的双层间接寻址?
有人能向我解释为什么?我读的全部是相信我,但我不能仅仅因为有人这样说就信任某些东西。
我想尽了办法,我无法找到任何错误出现:
#define mymacro(a) int a ## __LINE__
mymacro(prefix) = 5;
mymacro(__LINE__) = 5;
int test = prefix__LINE__*__LINE____LINE__; // fine
那么为什么做我需要做的是这样的,而不是(引自网页):
但是,当您使用##时,您需要双层间接寻址。 基本上你需要创建一个“标记粘贴”等 作为一个特殊的宏:
#define NAME2(a,b) NAME2_HIDDEN(a,b) #define NAME2_HIDDEN(a,b) a ## b
相信我这一点 - 你真的需要做 这个! (和请人写信给我说,有时候工作没有 间接的第二层尝试串联一个符号以 __ LINE__看看然后会发生什么。)
编辑:可能有人也解释了为什么他使用NAME2_HIDDEN
在下面声明之前?在我使用它之前,定义NAME2_HIDDEN
宏似乎更符合逻辑。这里有一些诡计吗?
的C规格的相关部分:
6.10.3.1参数替换
参数的函数宏的调用后已经确定, 参数替换发生。在替换列表中的参数,除非前面由# 或##预处理记号或后跟一个##预处理标记(见下文),是 由对应的参数替换后其中所含的所有宏已经 扩大。在被替换之前,每个参数的预处理标记是 完全宏替换,就好像它们构成了预处理文件的其余部分一样;没有其他 预处理令牌可用。
,决定是否要双间接与否的关键部分是第二句和其中的例外 - 如果该参数参与#
或##
操作(如mymacro
和NAME2_HIDDEN
的PARAMS ),那么在执行#
或##
之前,参数中的任何其他宏都不会被展开。另一方面,如果宏体中没有#
或##
(与NAME2
一样),则扩展参数中的其他宏。
所以它归结为你想要的 - 有时你希望所有的宏扩展FIRST,然后做#
或##
(在这种情况下,你想要双层间接寻址),有时你不希望先扩展宏(在这种情况下,您无法使用双层宏,因此您需要直接执行此操作。)
。我发现它非常令人不安,网站告诉我总是使用它......而在我的情况下,我从来不想以这种方式使用它。 – Rookie
__LINE__
是应该解析为当前行号的特殊宏。当你做一个记号膏__LINE__
直接,但是,它并没有得到一个机会来解决,所以你最终与令牌prefix__LINE__
代替,比如说,prefix23
,就像你可能会被期待,如果你会写这个代码狂野。
Chris Dodd对您问题的第一部分有很好的解释。至于第二部分,关于定义序列,简短的版本是#define
指令本身根本不被评估;只有在文件中的其他位置找到符号时才会对它们进行评估和扩展。例如:
#define A a //adds A->a to the symbol table
#define B b //adds B->b to the symbol table
int A;
#undef A //removes A->a from the symbol table
#define A B //adds A->B to the symbol table
int A;
第一int A;
变得int a;
,因为这是如何A
在文件中的该点被定义。两次扩展后第二个int A;
变为int b;
。它首先扩展为int B;
,因为A
在文件中的那个点被定义为B
。然后预处理器识别B
是检查符号表时的宏。 B
然后扩展为b
。
唯一重要的是符号在扩展点的定义,而不管定义在哪里。
噢,我只是觉得把它们按顺序放在你使用它们的位置会更合乎逻辑,不知何故对我更有意义。感谢您的解释。 – Rookie
声明宏的顺序并不重要,它们的使用顺序是。如果你在声明之前真的使用这个宏 - (在实际的代码中,不是在宏被保持休眠状态直到被召唤),那么你会得到一个错误的种类,但因为大多数理智的人不去做这些类型的东西,写一个宏,然后编写一个函数,使用一个尚未定义的宏,等等,等等......看起来你的问题不仅仅是一个问题,而是我只回答那一部分。我认为你应该把这一点再打破一点。
我从这里的所有链接中收集到的最不是非技术性的答案,以及链接的链接;)是单层间接macro(x) #x
将输入的宏名称串化,但是通过使用双层,它会将输入宏观的价值。
#define valueOfPi 3
#define macroHlp(x) #x
#define macro(x) macroHlp(x)
#define myVarOneLayer "Apprx. value of pi = " macroHlp(valueOfPi)
#define myVarTwoLayers "Apprx. value of pi = " macro(valueOfPi)
printf(myVarOneLayer); // out: Apprx. value of pi = valueOfPi
printf(myVarOTwoLayers); // out: Apprx. value of pi = 3
在printf(myVarOneLayer)
printf(myVarOneLayer)
会发生什么情况扩展到printf("Apprx. value of pi = " macroHlp(valueOfPi))
macroHlp(valueOfPi)
试图字符串化输入,输入本身不进行评估。生活中唯一的目的是接受输入并进行串联。因此,它扩展为"valueOfPi"
所以,发生在printf(myVarTwoLayers)
printf(myVarTwoLayers)
什么是扩大到printf("Apprx. value of pi = " macro(valueOfPi)
macro(valueOfPi)
没有字符串化操作,即不存在#x
在它的扩张,但有一个x
,所以它必须评估x
并将值输入到macroHlp
进行串化。它扩大到macroHlp(3)
这反过来将串数3,因为它使用#x
我不知道我明白你在问什么... –
我看到它有点不清楚,我会编辑。 – Rookie
@tenfour,完成。你可能知道我编辑部分的答案吗? – Rookie