名称呼叫与宏扩展呼叫之间的区别

时间:2019-06-22 15:49:35

标签: c parameter-passing callbyname

让我们假设我们以类似于C的语言编写以下代码。

f()

我想定义该程序的输出。 我不太了解按名称调用和按宏扩展调用方法之间的区别。

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

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

然后返回到backgroundColor功能,其输出为:1,4,9

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

但是宏扩展通话与该方法有何不同?它会发生什么变化?

2 个答案:

答案 0 :(得分:1)

没有什么比C语言中的“宏调用”更好的了。只有带有参数的宏。宏只是在文本上被预处理的令牌代替。

IMO宏仅在确实需要时才使用,在大多数情况下,最好使用内联函数。宏很难解压(因为编译器会编译预处理的.c文件)并且容易出错。

示例

#define SUB(a,b) a-b

和用法

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

结果将不是2,只有-8

答案 1 :(得分:0)

  

但是宏扩展通话与该方法有何不同?它会发生什么变化?

对于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++; }用作无限循环),并且可以强大地执行代码混淆(故意使代码难以阅读)。
  • 对于函数,编译器可以决定不内联函数以减小代码大小
  • 对于函数,您可以进行递归操作(对于宏,您无法进行递归-最终将导致文本数量无限)
  • 对于函数,您可以具有函数指针和/或具有外部函数(通过静态链接或动态链接,链接器可在其中指出函数的位置)。