casting a parameter as a reference

Hi all,

I usually write code in C but I'm currently doing some C++ and came across something along the lines of the code below. I don't fully understand C++ references so my question is what is C++ doing when it casts a parameter as a type reference? This code compiles but does not update A.

I appreciate any help.

void myFunction(short &A)
{
A=10;
}

void main()
{
int A=0;
myFunction((short&)A);
printf("A=%d\r\n",A); /* A=0 will be the output */
}
Last edited on
You should consider the cast an error. It probably don't work because of that bad cast.
I wrote the equivalent program, and it worked correctly. I used g++ to build it.

The reference acts similar to a pointer (actually, it's probably implemented as a pointer under the hood). So, the expectation is that A should be changed during the function call.

What may be happening in your situation is because A in main() is an int and the argument to myFunction is a reference to a short, the compiler might have created a temporary short before passing it to the function. That's just a guess.

One note. void main() is not legal C++. Many compilers are lazy and allow it, and many books promote its use. But it is illegal. Legal C++ requires that you use int main().

Also, when posting code, please use the code tags. They show up as "<>" in the Format box on the right.
The cast to short& is to satisfy the function argument of a reference to a short int. This code does update A.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
#include <iostream>

void myFunction(short &A)
{
  A=10;
}

int main() // main() in C++ always returns int
{
  int A=0;
  myFunction((short&)A);
  std::cout << A << std::endl;
  return 0;
}


Output is: 10
Last edited on
According to the C++ Standard "The result of the expression (T) cast-expression is of type T. The result is an lvalue if T is an lvalue reference type"

So using this expression (short&)A you get the reference to A which will be interpretated as short.
On the other hand using the expression (short)A will not allow to compile the statement

myFunction( (short)A);


because in this case a temporary unnamed object will be created which can be binded only with a const reference.
Last edited on
A reference is an alias, a second (third, fourth, etc) name of an object that already was given a name.

In this program, the line "int A=0;" creates an object of type int with the first name "A".

When you use the name of an object in an expression, you're essentially using a reference to it (technically an lvalue), so when you wrote A in the next line, the type of that A is "int&".

However, that function expects a short&, so someone decided to cast int& to short& with a C-style cast. The appropriate C++ style cast would have been reinterpret_cast<short&>(A).

Such cast is illegal because it breaks aliasing rules, so the compiler is allowed to do anything at all inside the function on the line A=10, which is where undefined behavior occurs:

Your compiler chose to do nothing, as far as we can tell, (so A remained zero),

Texan40's compiler chose to modify A (and apparently runs on little-endian architecture), so 10 was printed

My compilers printed 0 (gcc) and 655360 (xlc, acc, sun CC)

other compilers may do other things - they may crash if they want to, anything is allowed under undefined behavior.

The intent of the original programmer was likely to store the value 10 in the first sizeof(short) bytes of main's A.

(note that "void main" is not valid C++ either)

EDIT: there are no unnamed temporary objects involved, guys.
Last edited on
The cast is probably making a temporary. The compiler is probably doing something similar to this:
1
2
3
int A=0;
short temporary = A;
myFunction(temporary);


In which case the temporary is being modified, and not A.

Really, if the function takes a short&, you pretty much have to give it a short&. You can't give it an int&.


EDIT:

holy crap what happened, I thought there weren't any replies to this yet.
Last edited on
printf("A=%d\r\n",A); /* A=0 will be the output */


And result shall be 10 not 0.

I think that you get 0 because you compile your program as C program. You should it compile as C++ program.


@Disch
The cast is probably making a temporary


No it is incorrect. An lvelue reference will be created. So the original value will be changed.

@Cubbi
Such cast is illegal because it breaks aliasing rules, so the compiler is allowed to do anything at all inside the function on the line A=10, which is where undefined behavior occurs:


It is not undefined behavior. It is a defined behavior. The object will be interpretated as short.
Last edited on
vlad wrote:
It is not undefined behavior. It is a defined behavior.


Since you like quoting the standard, please read what happens after such cast.
And what shall I read? The standard does not say about an undefined behaviour in this case. So the result is expected and will be equal to 10.
vlad wrote:
The standard does not say about an undefined behaviour in this case

You are wrong. The standard says quite explicitly that the behavior is undefined (not the cast itself, it always succeeds, but the glvalue access afterwards, at A=10)
Last edited on
¿Who cares? The code is horrendous and should not be used.
I have found nothing that would say that the behavior of the example is undefined.
@ne555 Basic concepts such as this are pretty important to care about. Just like order of evaluation, the aliasing rules are mysteriously absent from most C++ (and C, where C++ got the idea) textbooks and courses.

Also I'd like to make a point that the standard is not a textbook, some otherwise obvious facts may be missing a helpful hyperlink.

Hint, the following program is implementation-defined, and no longer exhibits undefined behavior:

1
2
3
4
5
6
7
8
9
10
11
12
#include <stdio.h>
void myFunction(char& A)
{
    A=10;
}

int main()
{
    int A=0;
    myFunction( (char&)A );
    printf("A=%d\n", A);
}


because accessing any object through a reference to char is permitted.
Last edited on
Consider another example when you need to write the length of the string in the first two bytes of a character array.

1
2
3
4
5
6
7
8
9
10
void f( short &x, short length )
{
   x = length;
}

char s[256] = {};

// some filling of s starting from the third byte

f( ( short & ) s, length );
I think §3.10/10 in C++11 is the relevant part. This rule is often called the strict aliasing rule.
Last edited on
I do not understand why you reference to glvalue and not lvalue which will be the result of discussed casting.
An lvalue is a glvalue.
@Peter87 Spoilers!

@vlad: your sample also invokes undefined behavior. GCC was even nice enough to issue a warning, although the resulting binary behaved as you probably expected.

Topic archived. No new replies allowed.