0

我在下面有以下代码(类似 C 的语言)。我知道如何跟踪是否使用了按值传递或按引用传递,但也有按名称调用机制。谁能指导我如何追踪姓名呼叫?

int x=12,y=10;
void tswap(int pa, int pb) {
   int tmp;
   tmp=pa;
   pa=pb;
   pb=tmp;
   x=x+pa;
   x=x-pb;
   y++;
   printf("%d %d %d %d\n",pa,pb,x,y);
}
int main() {
    int a=4;
    tswap(x,a);
    printf("%d %d %d\n",x,y,a);
    tswap(++x,++y);
    printf("%d %d %d\n",x,y,a);
    return 0;
}

如果使用按值传递,则输出将如下所示:

4 12 4 11

4 11 4

12 5 12 13

12 13 4

4

1 回答 1

2

一般来说,C++ 不使用名称调用。按名称调用意味着函数的参数不会在函数调用时进行评估。它的行为就像参数将被替换到函数体中一样。

例子:

void foo(int a, int b) {
    int s = 0;
    for(int i=0; i<n; i++) {
        s += b;
    }
}

通常在 C++ 中,一个示例表达式的x = foo(3,bar(7));行为类似于:

int tmp = bar(7);
x = foo(3,tmp);

bar被评估一次并将结果提供给函数foo.

使用名称调用的语言可能会转换foo(3,bar(7));

void foo() {
    int s = 0;
    for(int i=0; i<3; i++) {
        s += bar(7);
    }
}

在第一种情况下,函数bar将被评估一次,在第二种情况下,它将被评估3次数。


但是,该规则也有例外。当函数声明已知时(例如对于模板和内联),优化器可以使用它来生成优化代码。

例子:

inline unsigned foo(unsigned a, unsigned b) {
    return a / b;
}

如果您调用a = foo(x,2);编译器将足够聪明,可以将其转换为a = x/2;然后再转换为a = x >> 1;.

这甚至到了这个例子:

inline int foo(int a, int b) {
    if(a == 0) return 0;
    else return b;
}

现在编译器确实可以转换x = foo(0,bar(17));x = 0;从不调用该函数bar。我认为只有在确保bar没有副作用的情况下才进行这种优化。


虽然 C++ 不使用名称调用,但您可以轻松地在 C++ 中使用这一理念。只需给你的函数一个函数对象/指针。

例子:

template<typename F>
int foo(int a, F b) {
    int s = 0;
    for(int i=0; i<a; i++) {
        s += b();
    }
}

现在有了foo(3, []() { static int i=0; return i++; }),其中第二个参数是 C++11 lambda,每次在代码中遇到 b 时都会对其进行评估。

于 2014-04-17T12:54:45.317 回答