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 */
}
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;
}
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.
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.
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.
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)
@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.
@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.