我试图理解将函数定义为宏,我有以下代码,我不确定我是否理解:
#define MAX(i, limit) do \
{ \
if (i < limit) \
{ \
i++; \
} \
} while(1)
void main(void)
{
MAX(0, 3);
}
据我所知,它试图将MAX
定义为两个数之间的区间,但是无限循环的意义何在?
我曾尝试将MAX
的值存储在main
函数内的变量中,但它显示错误消息expected an expression
4条答案
按热度按时间7xzttuei1#
你很困惑,因为这是一个陷阱问题。发布的代码没有任何意义。
MAX
宏确实扩展为无限循环,由于它的第一个参数是一个文本值,i++
扩展为0++
,这是一个语法错误。要吸取的教训是:宏是混乱的、容易出错的,并且不应该被用来替换函数。
jtw3ybtb2#
你必须明白,在你的代码进入编译器之前,它首先要通过一个预处理器。它基本上改变了你的文本代码。它改变代码的方式是由预处理器指令控制的(以
#
开始的行,例如#include
,#define
,...)。在您的示例中,您使用了
#define
指令,预处理器在任何地方找到MAX(i, limit)
都将替换为它的定义。预处理器的输出也是一个文本文件,但是做了一些修改。在您的示例中,预处理器将用
因此,在
#define
中编写函数与编写普通函数void max(int i, int limit) { ... }
是不同的。dgtucam13#
假设你有很多这样的语句
在一篇评论中,@the busybee将这种模式称为“饱和增量器”。
当你在代码中看到一个重复的模式时,你自然会倾向于封装这个模式。有时候这是个好主意,或者有时候如果尝试封装它会使事情变得更糟,那么就离开重复也没关系。
封装这种特殊模式的一种方法--我不会说我认为这是不是一种好方法--是定义一个类似函数的宏:
那你可以说
要将其作为类似函数的宏的一个原因是(与真函数相反)的一个特点是,宏可以“修改其参数”--在本例中,无论您给它的变量名是
var
--这是真函数所不能做到的。(也就是说,如果饱和增量器是一个true函数,那么根据设置方式的不同,你必须调用incr_max(&a, 10)
或a = incr_max(a, 10)
。)然而,类似函数的宏和末尾的分号有一个问题,我不打算在这里解释整个问题;有一个关于它的big long previous SO question。
应用另一个问题的教训,“改进的”
INCR_MAX
宏将是最后,在你的练习和这个SO问题之间的某个地方,结尾的
while(0)
不知何故被改成了while(1)
,这几乎是一个无意的错误,因为while(1)
在这个上下文中没有任何意义。lztngnrs4#
是的,你不明白是有原因的--这是垃圾。
经过预处理后,代码为
是的,不知道这个东西 * 应该 * 做什么。名称
MAX
暗示它应该计算两个参数中较大的一个,a la但很明显这不是它所做的,它没有定义两个数之间的间隔,它试图将第一个参数的值设置为第二个参数的值,但是用一种毫无意义的方式。
有三个问题(技术上是四个):
0++
-常量不能是++
或--
运算符的操作数;i
或者limit
是表达式,比如MAX(i+1, i+5)
,你会遇到同样的问题,比如++
运算符,你会遇到优先级问题;第四个(技术)问题是......使用宏作为函数。我知道,这是嵌入式世界,嵌入式世界希望最小化函数调用开销。这就是
inline
函数说明符应该给你买的东西,这样你就不必经历这种心痛。但是,好吧,也许您正在使用的系统可用的编译器不支持
inline
,所以您必须完成这个练习。但是你必须去找给你这个代码的人,礼貌而恭敬地问,“这是什么垃圾?”