0

假设我们有以下代码,其语言看起来很像 C。

 int A[2];

 A[0]=4;
 A[1]=7;

    void f(int x, int y) {
     x++; A[1]++; y++;
     printf(x, y, A[0], A[1]);
    }

    void main() {
     int k = 0;
     f(k, A[k]);
     print(k, A[0], A[1]);
    }

我想定义这个程序的输出。我还没有很好地理解按名称调用和按宏扩展方法调用之间的区别。

因此,在按名称调用方法中,将 k 初始化为 0,然后f()调用函数。x 等于“k”,y 等于“A[k]”。被调用函数中的第一个命令是x++将“k”的值增加 1。因此 k 等于 1。然后 A[1] 增加,因此 A[1] 变为 7+1=8。x,y 均不受影响。最后,我们有将y++“A[k]”的值增加 1 的命令,因此它将 A[1](因为现在 k=1)的值增加 1,所以 A[1] 现在变为 8+1 =9。

然后f()打印:1,9,4,9

然后我们回到main()打印的函数:1,4,9

所以,如果我没记错的话,程序的输出是 1,9,4,9,1,4,9。

但是宏扩展调用与此方法有何不同?它有什么变化?

4

2 回答 2

1

但是宏扩展调用与此方法有何不同?它有什么变化?

对于 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]);
}

然后预处理器会将文本从宏剪切并粘贴到宏的使用位置,然后用您提供的参数替换xy,这样(预处理后)源代码如下所示:

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++;修改副本而不是原件)。

于 2019-06-23T13:22:07.560 回答
1

C 语言中没有像“宏调用”这样的东西。只有带有参数的宏。宏只是在文本上被预处理的标记替换。

只有在真正需要时才应使用 IMO 宏,在大多数情况下,最好使用内联函数。宏很难 debus(因为编译器编译预处理的 .c 文件)并且容易出错。

例子

#define SUB(a,b) a-b

和用法

printf("%d", SUB(3-2,4-5));

结果不会只有 2 -8

于 2019-06-23T13:48:13.937 回答