3

我不是一个 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(); }

他们还讨论了动态范围规则如何应用于x宏中的名称a。我假设它基本上会替换a为然后编译程序,因此范围规则将与您编写的而不是(x + 1)完全相同(这将是静态范围规则)。(x + 1)a

有人可以澄清一下吗?

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

4

3 回答 3

2

您对#define 行为的理解是正确的。

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

这与词法范围(C 语言和几乎所有现代语言中实际使用的)形成对比,其中名称指的是其本地词法环境。例如,如果您将示例中的 #define 替换为 simple statement a = x+1,则函数中 a 的值将比a = x+1代码中出现的 x 值大一。如果在您使用值 a 的位置碰巧存在其他名为 x 的局部变量,则无关紧要。同样,如果你定义了一个函数int f() { return x + 1; }, x 将引用全局变量 x,而不是其他一些名为 x 的局部变量,它恰好存在于调用 f() 的位置。如果这看起来很明显,那是因为,正如我所说,几乎所有语言都使用词法作用域(尽管 Perl,例如,也允许使用该local函数的动态作用域)。

有关该概念的更多解释,请参见http://en.wikipedia.org/wiki/Scope_(computer_science)#Lexical_scoping_and_dynamic_scoping 。

于 2012-07-18T03:31:59.993 回答
2

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

关于类对象宏(like a),我们可以讨论的唯一“范围”是宏本身的范围:宏的范围是从定义它的行(使用#define指令)到该行如果它从未未定义,则它未定义(使用#undef指令)或直到翻译单元(.cpp 及其包含的所有头文件)的末尾。

于 2012-07-18T03:14:59.520 回答
1

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

于 2012-07-18T03:39:52.397 回答