我知道#define
具有以下语法:#define SYMBOL string
如果我写,例如
#define ALPHA 2-1
#define BETA ALPHA*2
然后ALPHA = 1
但是BETA = 0
。(为什么?)
但如果我写这样的话
#define ALPHA (2-1)
#define BETA ALPHA*2
然后ALPHA = 1
和BETA = 2
。
有人可以解释一下这两者之间有什么区别吗?
答案 0 :(得分:5)
使用#define
创建的预处理器宏是文本替换。
这两个例子并不相同。第一组将BETA
设置为2-1*2
。第二组将BETA
设置为(2-1)*2
。声称ALPHA == 1
并不正确,因为 ALPHA
不是数字 - 它是一个自由人!它只是一个字符序列。
当解析为C或C ++时,这两个表达式是不同的(第一个与2 - (1*2)
相同)。
我们可以通过打印BETA
的字符串扩展以及将其作为表达式进行评估来显示差异:
#ifdef PARENS
#define ALPHA (2-1)
#else
#define ALPHA 2-1
#endif
#define BETA ALPHA*2
#define str(x) str2(x)
#define str2(x) #x
#include <stdio.h>
int main()
{
printf("%s = %d\n", str(BETA), BETA);
return 0;
}
使用和不定义PARENS
编译上述内容以查看差异:
(2-1)*2 = 2
2-1*2 = 0
这样做的结果是,当使用#define
创建扩展为表达式的宏时,通常使用比通常需要的更多括号通常是个好主意,因为您不知道其中的上下文你的价值观将会扩大。例如:
#define ALPHA (2-1)
#define BETA ((ALPHA)*2)
答案 1 :(得分:3)
运营顺序。第一个例子变成2-1 * 2,等于2-2。 另一方面,第二个例子扩展为(2-1)* 2,其评估为1 * 2.
在第一个例子中:
#define ALPHA 2-1
#define BETA ALPHA*2
alpha直接代替你给它的任何值(在这种情况下,2-1)。 如上所述,这导致BETA扩展到(变为)2-1 * 2,其评估为0。
在第二个例子中:
#define ALPHA (2-1)
#define BETA ALPHA*2
Alpha(在BETA的定义范围内)扩展为设置为(2-1)的值,然后无论何时使用它都会使BETA扩展为(2-1)* 2。
如果您遇到操作顺序问题,您可以随时使用首字母缩写 PEMDAS 来帮助您(括号指数乘法除法减法),它本身可以记为& #34;请原谅我亲爱的莎莉姨妈&#34;。首字母缩略词中的第一个操作必须始终在缩写的后续操作之前完成(乘法和除法除外(在你的方程中你只是从左到右,因为它们被认为具有相同的优先级,并且添加和减法(与乘法和除法相同的场景)。
答案 2 :(得分:3)
宏(#define ...
)只是文本替换。
使用此版本:
#define ALPHA 2-1
#define BETA ALPHA*2
预处理器将BETA
替换为ALPHA*2
,然后将ALPHA
替换为2-1
。宏扩展结束后,BETA
将替换为2-1*2
,这是(由于运算符优先级)等于2-(1*2)=0
当您在ALPHA
&#34;的&#34; 值周围添加括号时(ALPHA
实际上没有值,因为宏只是文本替换),您更改操作的评估顺序。现在BETA
被(2-1)*2
替换,等于2。
答案 3 :(得分:2)
宏只是文本替换,而不是函数。所以宏只是用程序文本中的宏名称替换其内容之前编译器事件试图分析代码。所以在第一种情况下,编译器会看到:
BETA ==> ALPHA * 2 ==> 2 - 1 * 2 ==> compiler ==> 0
printf("beta=%d\n", BETA); ==> printf("beta=%d\n", 2 - 1 * 2);
在第二个
BETA ==> ALPHA * 2 ==> (2 - 1) * 2 ==> compiler ==> 2
printf("beta=%d\n", BETA); ==> printf("beta=%d\n", (2 - 1) * 2);