具有函数参数的C ++实际发生了什么?

时间:2015-09-23 00:49:45

标签: c++ function parameter-passing

过去几个月我一直在学习C ++。我知道函数你的第一个声明参数如下:

int myFunc(int funcVar);

然后您可以将整数变量传递给该函数,如下所示:

int x = 5;

myFunc(x);

将参数传递给函数时,我通常会想到将x的值分配并复制到myFunc的参数中,这在C ++中看起来像这样:

funcVar = x;

但是,当我声明具有引用(或指针)参数的函数时,我注意到了:

int myFunc(int & funcVar);

我可以将变量x传递给myFunc:

myFunc(x);

看起来像(在我看来):

&funcVar = x;

或者您可以传入实际引用作为参数

int & rX = x;

myFunc(rX);

并且该函数也可以正常工作,我的想法看起来像C ++中的这个语句

int & funcVar = rX

分配对引用的引用是没有意义的。我的问题是编译器如何实际加载函数中的参数?我不应该想到将变量的值赋值给函数的参数吗?

3 个答案:

答案 0 :(得分:1)

当你调用一个函数时,函数的每个参数都是初始化(未分配)。其规则与任何其他复制初始化的规则相同。所以,如果你有

funcVar

然后int funcVar = x; 初始化,好像是这样的语句:

int myFunc(int & funcVar);
myFunc(x);
int & rX = x;
myFunc(rX);

如果你有

funcVar

然后int & funcVar = x; int & funcVar = rX; 初始化(以及未分配),就好像这样的语句:

rX

引用的初始化将其绑定到初始化程序表示的对象或函数。第二次初始化确实有意义--- 表达式 x表示对象 rX,因为x是绑定到rX的引用{1}}。因此,使用x初始化引用与使用{{1}}初始化引用具有相同的效果。

答案 1 :(得分:1)

让我们轻松编写代码并进行反汇编。

int by_value(int x) { return x; }
int by_reference(int &x) { return x; }
int by_pointer(int *x) { return *x; }

int main()
{
    int x = 1;

    by_value(x);
    by_reference(x);
    by_pointer(&x);

    return 0;
}

$ g++ -g -O0 a.cpp ; objdump -dS a.out

在我的环境(x86_64,g ++(SUSE Linux)4.8.3 20140627)中,结果如下。 (全文在这里http://ideone.com/Z5G8yz

00000000004005dd <_Z8by_valuei>:

int by_value(int x) { return x; }
  4005dd:       55                      push   %rbp
  4005de:       48 89 e5                mov    %rsp,%rbp
  4005e1:       89 7d fc                mov    %edi,-0x4(%rbp)
  4005e4:       8b 45 fc                mov    -0x4(%rbp),%eax
  4005e7:       5d                      pop    %rbp
  4005e8:       c3                      retq   

00000000004005e9 <_Z12by_referenceRi>:
int by_reference(int &x) { return x; }
  4005e9:       55                      push   %rbp
  4005ea:       48 89 e5                mov    %rsp,%rbp
  4005ed:       48 89 7d f8             mov    %rdi,-0x8(%rbp)
  4005f1:       48 8b 45 f8             mov    -0x8(%rbp),%rax
  4005f5:       8b 00                   mov    (%rax),%eax
  4005f7:       5d                      pop    %rbp
  4005f8:       c3                      retq   

00000000004005f9 <_Z10by_pointerPi>:
int by_pointer(int *x) { return *x; }
  4005f9:       55                      push   %rbp
  4005fa:       48 89 e5                mov    %rsp,%rbp
  4005fd:       48 89 7d f8             mov    %rdi,-0x8(%rbp)
  400601:       48 8b 45 f8             mov    -0x8(%rbp),%rax
  400605:       8b 00                   mov    (%rax),%eax
  400607:       5d                      pop    %rbp
  400608:       c3                      retq   

0000000000400609 <main>:

int main()
{
  400609:       55                      push   %rbp
  40060a:       48 89 e5                mov    %rsp,%rbp
  40060d:       48 83 ec 10             sub    $0x10,%rsp
        int x = 1;
  400611:       c7 45 fc 01 00 00 00    movl   $0x1,-0x4(%rbp)

        by_value(x);
  400618:       8b 45 fc                mov    -0x4(%rbp),%eax
  40061b:       89 c7                   mov    %eax,%edi
  40061d:       e8 bb ff ff ff          callq  4005dd <_Z8by_valuei>
        by_reference(x);
  400622:       48 8d 45 fc             lea    -0x4(%rbp),%rax
  400626:       48 89 c7                mov    %rax,%rdi
  400629:       e8 bb ff ff ff          callq  4005e9 <_Z12by_referenceRi>
        by_pointer(&x);
  40062e:       48 8d 45 fc             lea    -0x4(%rbp),%rax
  400632:       48 89 c7                mov    %rax,%rdi
  400635:       e8 bf ff ff ff          callq  4005f9 <_Z10by_pointerPi>

        return 0;
  40063a:       b8 00 00 00 00          mov    $0x0,%eax
}

by_reference(x)与by_pointer(&amp; x)相同!

答案 2 :(得分:0)

将引用分配给另一个引用(首次定义它时,即在初始化时)以及实际发生的事情是非常有意义的。引用只是一个别名,因此当您为另一个引用分配引用时,您只是说第一个引用是您指定的引用的别名。实施例

int x = 42;
int& rx = x;
int& ry = rx;
++ry;
std::cout << x; // displays 43

Live on Coliru