1

Is this :

  void foo(int& x){
     ....
  }
     ....
  foo(arg);

the same as this :

  void foo(int * x){
     ....
  }
     ....
  foo(&arg);

Do they lead to the same result ? Is the argument in the first one also passed by reference ?

ouah
  • 142,963
  • 15
  • 272
  • 331
  • 1
    Nope, not the same. In the first case x is presumed to be an int, and is, indeed, passed by reference. In the second case, x is presumed to be a pointer to int. – Hot Licks Jul 29 '14 at 11:55
  • 2
    No. The first code is pass by reference and the second one is pass by pointer/address. Refer:http://stackoverflow.com/questions/3613065/when-to-pass-by-reference-and-when-to-pass-by-pointer-in-c – askmish Jul 29 '14 at 11:55
  • Is `int&` a C/C++ type ? If yes what does it actually means ? –  Jul 29 '14 at 11:57
  • 1
    Like the above comments say, it's not the same. They are similar though, because in both cases you can change the value of `x` in the function and the change will live on when the function returns. The references is very likely implemented as pointers by the compiler anyway, so most of the time the actual difference is just cosmetic. – Some programmer dude Jul 29 '14 at 11:57
  • 1
    Related: [What are the differences between pointer variable and reference variable in C++?](http://stackoverflow.com/questions/57483/what-are-the-differences-between-pointer-variable-and-reference-variable-in-c) – Felix Glas Jul 29 '14 at 11:58
  • 2
    "Is the argument in the first one also passed by reference ?" - ***also?*** It's **only** the first piece of code where the argument is passed by reference. In the second case, it's passed by value. – The Paramagnetic Croissant Jul 29 '14 at 11:58
  • @reaffer: "Is `int& a` C/C++ type ?" No, it's a C++ type, a reference to `int`. C is a different language, and doesn't have reference types. – Mike Seymour Jul 29 '14 at 13:05
  • References and pointers are indeed two different syntactic elements of the C++ grammar, but this difference makes sense only during syntaxic and semantic analysis. When generating the output assembly code, passing a pointer or a reference as a function parameter will produce the exact same ASM code. Indeed, they are both (in the end) the address where the data is stored in memory. See my answer for further details. – Zalgo Jul 29 '14 at 15:06

4 Answers4

3

The & sign can be used either with a type in a declaration, e.g. like this:

int& x; // #1

or before an identifier, e.g. like this:

&x // #2
  • The first variant means that you declare a variable as a reference (in this case a reference to int).

  • The second variant means that you call the address-of operator which returns the memory address of the data.

The two uses of & is entirely unrelated and has nothing to do with each other. They just use the same sign.


In your first example you declare a function taking a parameter by reference to int (& used when declaring type):

void foo(int& x) {
    /* ... */
}
/* ... */
foo(arg); // Pass 'arg' to function.

In your second example you declare a function taking a parameter by pointer to int, and later you use the address-of operator on arg before passing it (effectively passing the address of arg):

void foo(int* x) {
    /* ... */
}
/* ... */
foo(&arg); // Pass address of 'arg' to function.

Related:

Community
  • 1
  • 1
Felix Glas
  • 15,065
  • 7
  • 53
  • 82
0

I do think this is a good question, and i disagree with the other people reactions. In my opinion, both functions have an integer parameter passed by reference (i.e., the adress of the variable is pushed on the called stack). The use of the ampersand is simply C++ syntactic sugar that is not available in the C standard.

To convince you that these two syntax have exactly the same behavior, you may compile and desassembly the following code:

void function_1(int &x){
x=3;
}

void function_2(int *x){
*x=3;
}

int main(void){
return 0;
}

After compilation and desassembly with

g++ -g -Wall -Werror ptr.c -o ptr

and

objdump -D ptr > res.txt

, you get the following assembly sections:

00000000004004b4 <_Z10function_1Ri>:
  4004b4:    55                       push   %rbp
  4004b5:    48 89 e5                 mov    %rsp,%rbp
  4004b8:    48 89 7d f8              mov    %rdi,-0x8(%rbp)
  4004bc:    48 8b 45 f8              mov    -0x8(%rbp),%rax
  4004c0:    c7 00 03 00 00 00        movl   $0x3,(%rax)
  4004c6:    5d                       pop    %rbp
  4004c7:    c3                       retq  

00000000004004c8 <_Z10function_2Pi>:
  4004c8:    55                       push   %rbp
  4004c9:    48 89 e5                 mov    %rsp,%rbp
  4004cc:    48 89 7d f8              mov    %rdi,-0x8(%rbp)
  4004d0:    48 8b 45 f8              mov    -0x8(%rbp),%rax
  4004d4:    c7 00 03 00 00 00        movl   $0x3,(%rax)
  4004da:    5d                       pop    %rbp
  4004db:    c3                       retq  

The produced assembly code is indeed the same for both functions.

Zalgo
  • 100
  • 4
  • 3
    What you showed is that they *can* have the same behavior in some cases. But they don't always. For example, the pointer can be reassigned, or it can be null. – interjay Jul 29 '14 at 12:14
  • A reference is more than syntactic sugar. It is important to understand that (if you ever need to program in C++.) – juanchopanza Jul 29 '14 at 12:17
  • 1
    "In my opinion, both functions have an integer parameter passed by reference" - in your opinion? And what about the fact that the C++ standard disagrees with it? – The Paramagnetic Croissant Jul 29 '14 at 12:20
  • Well this is true, the first case is less permissive than the second one for the implementation of the function. However, the parameter passing mechanism is the same. – Zalgo Jul 29 '14 at 12:21
0

Do they lead to the same result? No. But in the both cases, x can be modified by the function. In the first one, you're passing x by reference. But in the second case, you're passing a pointer to an int. In the second case all the changes made to the pointer x will be local, but not the data is changed. That is, consider the following code,

void function_2(int *x)
{
   x = new int(3); // This change is local and doesn't affect the variable "arg"
   *x = 2;
}

int *arg;
function_2(arg);
cout << x; // OOPS! an error. This is because you're passing the pointer by value.

While this is not working, Zalgo's version of function_2 changes the value of x, because there the data pointed to by x is changed but in the above code, x itself is changed. Changing the above code to,

void function_2(int *&x) // Passing a reference to a pointer.
{
   x = new int(3); // This change is affects arg,
   *x = 2;
}

int *arg;
function_2(arg);
cout << x; // OK.

There are only two types of parameter passing, pass-by-reference and pass-by-value. There is no such thing as pass-by-pointer.

Fish
  • 1,205
  • 1
  • 10
  • 12
0

OK, OK, I've got it: passing a reference to a variable instead of passing a pointer is less permissive for the programmer in the function implementation (e.g., you can't modify a reference whereas the pointer can get reassigned within the function block). This is actually the answer to the author's second question, which is:

Is the argument in the first one also passed by reference ?

Now, let's have a look back at the author's first question:

Do they lead to the same result ?

In other terms, assuming we are in a context where both implementation are correct and compile successfuly, what are the differences between one execution and the other ?

The answer is: NONE.

Why ?

Because compilers implement the reference parameter passing in the EXACT SAME WAY than pointer parameters! From an assembly point of view, you just want to push the damn address of the integer (or whatever kind of data) on the top of the function's stack frame. This address eventually gets dereferenced when loading/storing the data. This is the same thing when using references in other declarations.

www.edn.com/Pdf/ViewPdf?contentItemId=4024641 :

The C++ standard is very careful to avoid dictating how a compiler must implement references, but every C++ compiler I've seen implements references as pointers. That is, a declaration such as:

int &ri = i;

if it's not optimized away entirely, allocates the same amount of storage as a pointer, and places the address of i into that storage.

Once again, check the assembly code if you're not convinced:

void function_1(int &x){
x=3;
}

void function_2(int *x){
*x=3;
}

g++ -g -Wall -Werror ptr.c -o ptr
objdump -D ptr > res.txt

00000000004004b4 <_Z10function_1Ri>:
  4004b4:    55                       push   %rbp
  4004b5:    48 89 e5                 mov    %rsp,%rbp
  4004b8:    48 89 7d f8              mov    %rdi,-0x8(%rbp)
  4004bc:    48 8b 45 f8              mov    -0x8(%rbp),%rax
  4004c0:    c7 00 03 00 00 00        movl   $0x3,(%rax)
  4004c6:    5d                       pop    %rbp
  4004c7:    c3                       retq  

00000000004004c8 <_Z10function_2Pi>:
  4004c8:    55                       push   %rbp
  4004c9:    48 89 e5                 mov    %rsp,%rbp
  4004cc:    48 89 7d f8              mov    %rdi,-0x8(%rbp)
  4004d0:    48 8b 45 f8              mov    -0x8(%rbp),%rax
  4004d4:    c7 00 03 00 00 00        movl   $0x3,(%rax)
  4004da:    5d                       pop    %rbp
  4004db:    c3                       retq   

"C++ references" are just syntactic elements introduced by the C++ grammar in order to restrict the manipulations you can do on the address of a variable. At register level, reference = pointer = address.

Zalgo
  • 100
  • 4