C++ c预处理器中的宏危害

C++ c预处理器中的宏危害,c++,c,macros,c-preprocessor,C++,C,Macros,C Preprocessor,我定义了以下宏 #define abss(a) a >= 0 ? a : -a 在调用此命令时 int b=-1; int c = abss(b); printf("%d\n",c); 它应该以b>=0的形式替换?b:-b,应该输出-2,但它在我的bloodhed/DevC++编译器1中输出 我分析C语言是为了考试,所以我必须知道上面的例子在C语言中到底发生了什么。输出结果1是针对我正在使用的CPP编译器还是什么 #define neg(a) -a int b = -1; neg(b

我定义了以下宏

#define abss(a) a >= 0 ? a : -a
在调用此命令时

int b=-1;
int c = abss(b);
printf("%d\n",c);
它应该以b>=0的形式替换?b:-b,应该输出-2,但它在我的bloodhed/DevC++编译器1中输出

我分析C语言是为了考试,所以我必须知道上面的例子在C语言中到底发生了什么。输出结果1是针对我正在使用的CPP编译器还是什么

#define neg(a) -a

int b = -1;
neg(b);
在上述情况下,预处理器将宏扩展为-b,结果是值为1。预处理器甚至不会意识到b的内容的符号是负数,那么第二个-应该从哪里来形成前缀减量运算符呢

即使你是这样写的:

 neg( -b );
int c = b >= 0 ? b : -b + 123;
 #define abss(a) ((a) >= 0 ? (a) : -(a))
宏替换是在令牌级别完成的,而不是文本搜索和替换。你会得到相当于--b的值,但不是-b

编辑:您在其他评论中链接到的手册已经过时,甚至没有涉及C99标准,而且非常糟糕。只要浏览一下,我就发现了半打陈述,如果你认为它们是正确的,那么它们会让你看起来很愚蠢。除了点火以外,不要使用它。

您的宏将扩展到

b >= 0 ? b : -b;
不到b>=0?b:--b;或者不管你期望什么

你的意思是

int x = -4;
-x; 
应该减量x吗

底线-尽可能避免使用宏。

您的代码

int b=-1;
int c = abss(b);
printf("%d\n",c);
由预处理器转换为:

int b=-1;
int c = b >= 0 ? b : -b;
printf("%d\n",c);

int b=-1在C域中,而abssb在编译器到达int b=-1之前由预处理器进行扩展。宏处理器将永远不会将两个相邻的标记连接在一起,即使它们之间没有空格,因此实际上,正如其他海报所提到的,宏将扩展为-b或1

如果您希望两个令牌在被预处理器扩展时变为一个,则必须使用令牌粘贴操作符,如

#define abss(a) a >= 0 ? a : - ## a

这确实可以满足您的需要,因为负号和变量将形成一个标记。不幸还是幸运,取决于你如何看待它!粘贴的令牌-b将无效,扩展将无法编译。

您认为它究竟为什么应该输出-2

#define abss(a) a >= 0 ? a : -a
因此: int c=abssb

变成 INTC=b>=0?b:-b

b是-1,因此计算结果为1

顺便说一句,您应该将宏参数的每次使用都括起来,因为您可能会通过诸如x+1之类的程序。这会让人觉得很奇怪


更不用说abss++x的结果了,您获得该行为的原因是预处理器只会将a替换为b,因此预处理后的代码实际上如下

b >= 0 ? b : -b
而不是

b >= 0 ? b : --b
所以,如果b=-1,那么它将被有效地视为--1,从而变为1

您可以检查预处理器输出并亲自查看。

此宏

#define abss(a) a >= 0 ? a : -a
确实很危险,但危险并不是你想象的那样。你帖子里的表达

int c = abss(b);
很好用。但是,考虑当表达式不是简单变量,而是一个难以计算的函数,或者当它是带有副作用的表达式时会发生什么。比如说

int c = abss(long_calc(arg1, arg2));

如果abss是一个函数,那么所有三个调用都将在可预测的时间内产生良好的结果。但是,宏会使第一个调用调用invoke long_calc并两次询问用户,如果用户在再次提示时输入不同的号码怎么办?并且它会两次post递增b

P>此外,考虑这个看似简单的表达式:

int c = abss(b) + 123;
因为+的优先级高于?:,由此产生的扩展将如下所示:

 neg( -b );
int c = b >= 0 ? b : -b + 123;
 #define abss(a) ((a) >= 0 ? (a) : -(a))
当b为正时,123将不会被添加,因此表达式的含义将发生显著变化

最后一个缺点可以通过将表达式括在括号中来解决。还应将每个宏参数用括号括起来,如下所示:

 neg( -b );
int c = b >= 0 ? b : -b + 123;
 #define abss(a) ((a) >= 0 ? (a) : -(a))

你还没有回答这个问题——为什么会这样。这只是问题出现的另一个例子。实际上,你得到了-b。为什么会有关于-b的讨论?@LuchianGrigore:答案扩大了。是您期望代码会导致减量,而您的假设是错误的。@LuchianGrigore:……当然,除非您键入了错误的宏。@DevSolar:问题是:它应该以b>=0的形式替换吗?b:-b。注意减量运算符。问题中有一个输入错误,或者是在提问者期望的解释的初始宏观定义中。你可能先读一些东西。。。。我的意思是关于C/C++。请不要再阅读你一直链接到的手册。除了坏的、无用的、误导性的、精神错乱的、脑死亡的,这是20多年来我在这个主题上看到的最糟糕的工作之外,它是{删除了粗俗的术语}。我在宇宙软件的C语言手册的预处理器6-5部分发现了这个扩展,你可以检查一下@阿拉米尼奥赛因:两点。第一:那本手册是错的,可能是淘汰了第一个C预处理器b
但那是在ANSI标准之前,那是23年前的事了。第二:你复制的例子是错误的。宏参数中的-将直接出现在展开中,但-用于初始化将成为参数的变量时不会出现,因为预处理器仅使用变量的名称。您给出的示例是编译时工作。但宏扩展发生在编译之前。。。如何比较它们?@alaminhosain,因为宏扩展到完全相同的东西:-b.@alaminhosain:快速搜索,甚至访问维基百科,将为您提供大量的在线和离线资料。Kernighan&Ritchie C编程语言是关于这个主题的一本开创性的书。我没想到会有输出-2。当我读到宇宙软件公司的c语言手册时,我确实认为编译器会输出错误……你们可以在预处理器的第6-5节中检查这一点……在abssb(其中b=-1)和abss-b(其中b为1)之间有细微的区别。请注意,您正在向宏传递两个不同的文本字符串。您编写的代码与本书中的示例完全不同。请仔细阅读本书中的解释。此外,正如Steve在上文中所说,如果你的编译器这样做了,那么它就不是完全标准的,因为它不是以那种方式粘贴符号的。请在预处理器的第6-5节检查这一点…@alaminhosain:首先,手册是错误的。如果它准确地描述了宇宙编译器的功能,那么编译器就错了。在他们的例子中,ABS-b不是扩展到-b>=0-b:-b,实际上它扩展到-b>=0-b:-b。其次,你没有遵循手册中的示例,因为你没有使用abssb而不是abss-b。在编码之前,我假设这是因为这是关于编码的常识……但是你能检查一下预处理器第6-5节中关于将-b传递给宏的第6-5节吗。但是,在您的示例中,您通过了分配为-1的b。如果你通过了-b,那么你将得到书中提到的结果。希望你明白了。