tags:

views:

266

answers:

6

I wanted to know how the following works @ compiler level.

int const iVal = 5; 
(int&)iVal = 10;

A bit of m/c or compiler level answer would be great full.

Thanks in advance.

+4  A: 

Why not run it through your cown ompiler and look at the assember output?

anon
Neil, VC7 compiles it allright. It even runs it allright in Debug mode. In Release mode iVal value doesn't change.
sharptooth
Upvoted for being downvoted for no reason. This post makes a lot of sense - if OP really wants to know (which I doubt) what code compiler generates, disassembling compiler output is a best approach.
qrdl
Since this is undefined behavior, different compilers are allowed to do different things - the result from one compiler is relatively useless.
snemarch
@snemarch - the questioner is asking specifically about machine code, so this seems the best solution. I was aware the code was illegal and my original reply pointed this out - for which I got downvoted - you can't win!
anon
don't be worried about downvoters. i would have voted you up again and others too, i'm sure. i mean what does it help when he has invalid C++ code and asks how it internally "works"?
Johannes Schaub - litb
+8  A: 

It is undefined behavior.

In the first line you define a constant integer. Henceforth, in your program, the compiler is permitted to just substitute iVal with the value 5. It may load it from memory instead, but probably won't, because that would bring no benefit.

The second line writes to the memory location that your compiler tells you contains the number 5. However, this is not guaranteed to have any effect, as you've already told the compiler that the value won't change.

For example, the following will define an array of 5 elements, and print an undefined value (or it can do anything it wants! it's undefined)

int const iVal = 5;
(int&)iVal = 10;
char arr[iVal];
cout << iVal;

The generated assembly might look something like:

sub ESP, 9      ; allocate mem for arr and iVal. hardcoded 5+sizeof(int) bytes
                ; (iVal isn't _required_ to have space allocated to it)
mov $iVal, 10   ; the compiler might do this, assuming that you know what
                ; you're doing. But then again, it might not.
push $cout
push 5
call $operator_ltlt__ostream_int
add ESP, 9
+5  A: 

C-style cast acts as a const_cast. Like if you've written

const_cast<int&>( iVal ) = 10;

If you happen to do so and the compiler decides not to allocate actual memory for iVal, you run into undefined behaviour.

For example, VC7 compiles it allright. It even runs it allright in Debug mode. In Release mode iVal value doesn't change after the assignment – it remains 5.

So you should not do so ever.

sharptooth
+1  A: 

This is possible because the idea of "const-ness" only exists in the language/compiler. In actual computer memory, everything is variable. Once the code has been compiled, your iVal variable is simply a location in RAM.

edit: the above assumes that the constant is actually placed in memory. See sharptooth's answer.

Using the c-style cast tells the compiler to treat this memory location as if it were a simple integer variable, and set that value to 10.

e.James
"this works"? not really!
Good point. I'll change the wording.
e.James
Compiler may place const into read-only memory segment (if supported by OS), so it is not just language issue.
qrdl
A: 

Undefined behavior.

In release builds, most compilers will substitute the const value directly - but you could run into one that does a memory load. Also, the second assignment might or might not generate an access violation, depending on platform and compiler. Iirc Intel's compiler puts const data in read-only memory, and would thus generate an access violation at runtime.

snemarch
A: 

If this were an embedded system, it's likely that iVal would be stored in flash, so writing to it would have no effect.

However, it is possible that the compiler would not regard this an error, as embedded compilers generally don't keep track of whether a particular area of memory is readable or not.

I suspect that it might pass the linker too, as a linker will typically determine that iVal is a constant, so goes in flash - but it's not the linker's job to determine how iVal is used.

Incidentally, this question is tagged with "C", but the "(int&)" syntax is not (AFAIK) valid C. The same could, however, be achived with something like:

int *Ptr = (int *) &iVal;
*Ptr = 10;
Steve Melnikoff