C宏的作用域规则

C宏的作用域规则,c,macros,C,Macros,我不是一个C程序员,但我认为C宏几乎是一种查找和替换功能,预处理器将宏定义放在它看到宏名称的任何地方 这是Dragon Book的动态范围规则示例,以及它们如何应用于宏: #define a (x + 1) int x = 2; void b () { int x = 1; printf("%d\n", a); } void c () { printf("%d\n", a); } void main () { b(); c(); } 他们还讨论了动态范围规则如何应用于宏a中的名称x。我的假设

我不是一个C程序员,但我认为C宏几乎是一种查找和替换功能,预处理器将宏定义放在它看到宏名称的任何地方

这是Dragon Book的动态范围规则示例,以及它们如何应用于宏:

#define a (x + 1)

int x = 2;
void b () { int x = 1; printf("%d\n", a); }
void c () { printf("%d\n", a); }
void main () { b(); c(); }
他们还讨论了动态范围规则如何应用于宏
a
中的名称
x
。我的假设是,它基本上将
a
替换为
(x+1)
,然后编译程序,因此范围规则将与您编写的
(x+1)
完全相同,而不是
a
(这将是静态范围规则)

有人能澄清一下吗


编辑:参考的书是《编译器:原理、技术和工具》第二版。引用的示例来自第31-32页。

您的理解是正确的:找到标识符
a
的所有用法,并用
(x+1)
替换该
a
。这正是预处理器所做的

对于像宏这样的对象(比如
a
),我们可以讨论的唯一“范围”是宏本身的范围:宏的范围是从定义它的行(使用
#define
指令)到未定义它的行(使用
#unde
指令)或者直到翻译单元结束(包括.cpp和它包含的所有标题),如果它从未被定义。

您对#定义行为的理解是正确的

我认为这本书所说的“动态范围”的意思是,x的名称是根据调用宏的环境而不是定义宏的环境来解析的。因此,如果您在#define之前设置了一个全局变量x=3,这与#define中的x值无关-它只会在使用宏的任何地方使用x值-如果在使用宏的函数中存在其他局部变量x,则将使用局部值

这与词法范围界定(实际上在C语言和几乎所有现代语言中都使用词法范围界定)形成对比,在词法范围界定中,名称指的是其本地词法环境。例如,如果将示例中的#define替换为简单语句
a=x+1
,则函数中a的值将比代码中出现
a=x+1
时x的值多一个。如果在使用值a的地方碰巧存在另一个名为x的局部变量,这并不重要。类似地,如果定义了一个函数
intf(){return x+1;}
,那么x将引用全局变量x,而不是调用f()时碰巧存在的另一个名为x的局部变量。如果这看起来非常明显,那是因为,正如我所说,几乎所有语言都使用词法作用域(例如,尽管Perl也允许使用
local
函数进行动态作用域)


有关该概念的更多解释,请参阅。

他们的观点是,a所指的x在b()中是局部的,但在c()中是全局的——它的作用域是动态的。#define可以解释为“在评估a时使用动态范围来解析x”。

我不明白为什么要讨论动态范围规则以及它们如何应用于x……这个答案没有解决关于澄清Aho等人的示例的问题,也没有抓住它的全部要点。请看happydave的回答或我简洁的回答。我想我理解了动态作用域和词汇作用域的区别——我主要感到困惑的是,为什么他们使用c宏来解释它,因为在实际编译程序时,宏早已消失,而语句x+1就在它的位置上。不过,这是一个很好的解释。我同意,我从未真正听说过“动态作用域”这个术语应用于宏。但我想,从概念上讲,预处理步骤是一个实现细节——事实上,预处理器让您能够创建动态范围的名称,这就是预处理器的真正功能(部分)的来源。没错,我想我只是把这个例子看得太字面了。只要我没有遗漏一些奇怪的细节。谢谢@用户12345613他们使用C宏来解释它,因为在熟悉的语言中,这是一个简单而明显的动态作用域示例。您对C编译器的工作方式做出的假设不一定正确,也不相关。许多C编译器不会在整个源代码中进行宏替换,然后对其进行编译,它们会在遇到宏时展开宏,并根据需要将其传递给语法分析器。它的编译方式并不影响x的抽象,它们正在处理的是动态作用域。但这确实是我的困惑所在,因为如果预处理器将a替换为x+1,则无法解析x。对吧?你犯了一个程序员的基本错误,“在大脑上实现”。你应该更抽象地思考。想象一下C的一个子集,其中没有宏的文本替换,但给定的示例是有效的——只有名称可以定义,并且只有格式良好的表达式。a的值是用x来定义的。哪个x?它的作用域是动态的。我认为你可能犯了另一个错误,可能被称为“坚持己见”。你说你很困惑,但你似乎在暗示一个人应该困惑。。。阿霍等人的例子是坏的或错误的。考虑到他们可能比你更了解这个问题,在这种情况下,你应该更加努力地把他们的例子看作是有效的而不是寻求反对它。“吉姆好点。然而,我并不真的认为我是在“坚持己见”。我发了一篇关于它的帖子,因为我真的很困惑。我正在阅读任何一本编译器书籍的第一章,我想我会努力理解他们为什么选择这个例子。这里的答案表明我对宏的理解是正确的,这使得