C语言 C 宏定义可以引用其他宏吗?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/7972785/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Can a C macro definition refer to other macros?
提问by llakais
What I'm trying to figure out is if something such as this (written in C):
我想弄清楚的是,是否有这样的东西(用C编写):
#define FOO 15
#define BAR 23
#define MEH (FOO / BAR)
is allowed? I would want the preprocessor to replace every instance of
被允许?我希望预处理器替换每个实例
MEH
with
和
(15 / 23)
but I'm not so sure that will work. Certainly if the preprocessor only goes through the code once then I don't think it'd work out the way I'd like.
但我不太确定这会起作用。当然,如果预处理器只通过一次代码,那么我认为它不会像我想要的那样工作。
I found several similar examples but all were really too complicated for me to understand. If someone could help me out with this simple one I'd be eternally grateful!
我发现了几个类似的例子,但都太复杂了,我无法理解。如果有人能帮我解决这个简单的问题,我将永远感激不尽!
采纳答案by Mysticial
Short answer yes. You can nest defines and macros like that - as many levels as you want as long as it isn't recursive.
简短的回答是。您可以像这样嵌套定义和宏 - 只要它不是递归的,就可以嵌套任意数量的级别。
回答by Keith Thompson
The answer is "yes", and two other people have correctly said so.
答案是肯定的,另外两个人也说对了。
As for whythe answer is yes, the gory details are in the C standard, section 6.10.3.4, "Rescanning and further replacement". The OP might not benefit from this, but others might be interested.
至于为什么答案是肯定的,详细信息在C 标准6.10.3.4 节“重新扫描和进一步替换”中。OP 可能不会从中受益,但其他人可能会感兴趣。
6.10.3.4 Rescanning and further replacement
After all parameters in the replacement list have been substituted and # and ## processing has taken place, all placemarker preprocessing tokens are removed. Then, the resulting preprocessing token sequence is rescanned, along with all subsequent preprocessing tokens of the source file, for more macro names to replace.
If the name of the macro being replaced is found during this scan of the replacement list (not including the rest of the source file's preprocessing tokens), it is not replaced. Furthermore, if any nested replacements encounter the name of the macro being replaced, it is not replaced. These nonreplaced macro name preprocessing tokens are no longer available for further replacement even if they are later (re)examined in contexts in which that macro name preprocessing token would otherwise have been replaced.
The resulting completely macro-replaced preprocessing token sequence is not processed as a preprocessing directive even if it resembles one, but all pragma unary operator expressions within it are then processed as specified in 6.10.9 below.
6.10.3.4 重新扫描和进一步更换
在替换列表中的所有参数都被替换并进行了#和##处理之后,所有的地标预处理标记都将被删除。然后,重新扫描生成的预处理标记序列以及源文件的所有后续预处理标记,以替换更多宏名称。
如果在替换列表的这次扫描期间找到被替换的宏的名称(不包括源文件的其余预处理标记),则不会替换它。此外,如果任何嵌套替换遇到被替换的宏的名称,则不会替换它。这些未替换的宏名称预处理标记不再可用于进一步替换,即使稍后在宏名称预处理标记将被替换的上下文中(重新)检查它们。
生成的完全被宏替换的预处理标记序列不会作为预处理指令处理,即使它类似于一个预处理指令,但其中的所有 pragma 一元运算符表达式将按照下面的 6.10.9 中的规定进行处理。
回答by Sauleil
Yes, it's going to work.
是的,它会起作用。
But for your personal information, here are some simplified rules about macros that might help you (it's out of scope, but will probably help you in the future). I'll try to keep it as simple as possible.
但是对于您的个人信息,这里有一些关于宏的简化规则可能会对您有所帮助(这超出了范围,但将来可能会对您有所帮助)。我会尽量保持简单。
The defines are "defined" in the order they are included/read. That means that you cannot use a define that wasn't defined previously.
Usefull pre-processor keyword: #define, #undef, #else, #elif, #ifdef, #ifndef, #if
You can use any other previously #define in your macro. They will be expanded. (like in your question)
Function macro definitions accept two special operators (# and ##)
定义是按照它们被包含/读取的顺序“定义”的。这意味着您不能使用之前未定义的定义。
有用的预处理器关键字:#define、#undef、#else、#elif、#ifdef、#ifndef、#if
您可以在宏中使用任何其他以前的 #define。它们将被扩展。(就像你的问题)
函数宏定义接受两个特殊运算符(# 和 ##)
operator # stringize the argument:
operator # 字符串化参数:
#define str(x) #x
str(test); // would translate to "test"
operator ## concatenates two arguments
运算符 ## 连接两个参数
#define concat(a,b) a ## b
concat(hello, world); // would translate to "helloworld"
There are some predefined macros (from the language) as well that you can use:
您还可以使用一些预定义的宏(来自语言):
__LINE__, __FILE__, __cplusplus, etc
See your compiler section on that to have an extensive list since it's not "cross platform"
请参阅您的编译器部分以获得广泛的列表,因为它不是“跨平台”
- Pay attention to the macro expansion
- 注意宏展开
You'll see that people uses a log of round brackets "()" when defining macros. The reason is that when you call a macro, it's expanded "as is"
您会看到人们在定义宏时使用圆括号“()”的日志。原因是当您调用宏时,它会“按原样”展开
#define mult(a, b) a * b
mult(1+2, 3+4); // will be expanded like: 1 + 2 * 3 + 4 = 11 instead of 21.
mult_fix(a, b) ((a) * (b))
回答by Stefan Monov
I'd like to add a gotcha that tripped me up.
我想添加一个让我绊倒的陷阱。
Function-style macros cannotdo this.
函数风格的宏不能做到这一点。
Example that doesn't compile when used:
使用时无法编译的示例:
#define FOO 1
#define FSMACRO(x) FOO + x
回答by Alexander Samoylov
Yes, and there is one more advantage of this feature. You can leave some macro undefined and set its value as a name of another macroin the compilation command.
是的,此功能还有一个优点。您可以保留一些未定义的宏并将其值设置为编译命令中另一个宏的名称。
#define STR "string"
void main() { printf("value=%s\n", VALUE); }
In the command line you can say that the macro "VALUE" takes value from another macro "STR":
在命令行中,您可以说宏“VALUE”从另一个宏“STR”中获取值:
$ gcc -o test_macro -DVALUE=STR main.c
$ ./test_macro
Output:
输出:
value=string
This approach works as well for MSC compiler on Windows. I find it very flexible.
这种方法也适用于 Windows 上的 MSC 编译器。我觉得它非常灵活。
回答by Mike Dinescu
Yes, that is supported. And used quite a lot!
是的,这是支持的。而且用的挺多的!
One important thing to note though is to make sure you paranthesize the expression otherwise you might run into nasty issues!
但是要注意的一件重要事情是确保您对表达式进行了注释,否则您可能会遇到令人讨厌的问题!
#define MEH FOO/BAR
// vs
#define MEH (FOO / BAR)
// the first could be expanded in an expression like 5 * MEH to mean something
// completely different than the second

