但是宏扩展调用与此方法有何不同?它有什么变化?
对于 C,“宏扩展调用”不存在。相反,对于宏,预处理器对原始文本执行美化的“剪切和粘贴”操作。
例如,如果你有这个:
int A[2];
A[0]=4;
A[1]=7;
#define MACRO(x, y) { \
x++; A[1]++; y++; \
printf(x, y, A[0], A[1]); \
}
void main() {
int k = 0;
MACRO(k, A[k]);
print(k, A[0], A[1]);
}
然后预处理器会将文本从宏剪切并粘贴到宏的使用位置,然后用您提供的参数替换x
和y
,这样(预处理后)源代码如下所示:
int A[2];
A[0]=4;
A[1]=7;
void main() {
int k = 0;
{ \
k++; A[1]++; A[k]++; \
printf(k, A[k], A[0], A[1]); \
}
print(k, A[0], A[1]);
}
当然,宏不需要包含有效代码,源代码甚至根本不需要是 C(例如,您可以使用预处理器来预处理汇编语言源代码,告诉编译器“不要编译,只需输出预处理后的文本"); 并且没有真正的理由为什么您不能使用完全不同的预处理器(具有完全不同的功能和/或宏语法)并将生成的文本输入 C 编译器(告诉编译器“不要预处理,只需编译”)。
在实践中; 宏和函数的主要区别是:
- 对于宏,没有对参数进行类型检查,因此错误最终会更烦人
- 对于宏,调试器只会说出宏被扩展的行号,而不会说出代码实际来自哪里,因此最终发现错误会更烦人
- 对于宏,因为它们不必是有效的 C,你可以做一些奇怪的恶作剧(例如
#define forever while(1) {
,你可以forever i++; }
用作无限循环),并且可以强大的代码混淆(故意使代码难以阅读)。
- 对于函数,编译器可以决定不内联函数以减少代码大小
- 对于函数,你可以有递归(你不能使用宏 - 它最终会成为无限量的文本)
- 对于函数,您可以拥有函数指针和/或外部函数(链接器通过静态链接或动态链接确定函数的位置)。
对于 (a) 差异的更简单示例,请考虑以下代码:
#define f(x) { \
x++; \
}
void g(int x) {
x++;
}
void main() {
int a = 1;
int b = 1;
f(a);
printf("%d\n", a);
g(b);
printf("%d\n", b);
}
这些看起来一样,但不是。扩展宏并内联函数后,它变得更像这样:
void main() {
int a = 1;
int b = 1;
a++;
printf("%d\n", a); // Will print "2' because the original `a` was changed
int x = b;
x++;
printf("%d\n", b); // Will print "1' because the original `b` was not changed
}
请注意,这与上面的示例完全相同(对于宏,x++;
修改原件k
而不是原件的副本k
;对于函数,x++;
修改副本而不是原件)。