Solved

Why the output is 10 ? const int num = 20;   (int &)num=10; cout<<(long &)num;

Posted on 2003-11-30
27
608 Views
Last Modified: 2010-04-01
Hi.Experts:
i find:
     const int num = 20;
     (int &)num=10;
     cout<<(long &)num;
     cout<<(int &)num;
     cout<<num;
the assembly code in Release build:
00401000   push        0Ah
00401002   mov         ecx,offset std::cout (00427318)
00401007   call        std::basic_ostream<char,std::char_traits<char> >::operator<< (00401260)
6:                const int num = 20;
7:                (int &)num=10;
8:                cout<<(long &)num;
9:                cout<<(int &)num;
0040100C   push        14h
0040100E   mov         ecx,offset std::cout (00427318)
00401013   call        std::basic_ostream<char,std::char_traits<char> >::operator<< (00401030)
10:               cout<<num;
00401018   push        14h
0040101A   mov         ecx,offset std::cout (00427318)
0040101F   call        std::basic_ostream<char,std::char_traits<char> >::operator<< (00401030)

How do compiler to know  0Ah of "push 0Ah"????
0
Comment
Question by:TKD
  • 9
  • 6
  • 5
  • +4
27 Comments
 
LVL 19

Expert Comment

by:Dexstar
ID: 9848452
@TKD:

> How do compiler to know  0Ah of "push 0Ah"????

This is interesting.  Look what happens when you comment out line #7:
      110:             const int num = 20;
      111:             //(int &)num=10;
      112:             cout<<(long &)num;
      00401490 6A 14            push        14h  
      00401492 B9 5C 8B 42 00   mov         ecx,offset std::cout (428B5Ch)
      00401497 E8 64 FE FF FF   call        std::basic_ostream<char,std::char_traits<char> >::operator<< (401300h)
      113:             cout<<(int &)num;
      0040149C 6A 14            push        14h  
      0040149E B9 5C 8B 42 00   mov         ecx,offset std::cout (428B5Ch)
      004014A3 E8 58 FE FF FF   call        std::basic_ostream<char,std::char_traits<char> >::operator<< (401300h)
      114:             cout<<num;
      004014A8 6A 14            push        14h  
      004014AA B9 5C 8B 42 00   mov         ecx,offset std::cout (428B5Ch)
      004014AF E8 4C FE FF FF   call        std::basic_ostream<char,std::char_traits<char> >::operator<< (401300h)

Which is what I would expect.  I have no idea where it gets the value of 0Ah in your example, or why it only uses it for the first call.  Can anyone fill here?

Dex*


Dex*
0
 
LVL 1

Expert Comment

by:Gratch06
ID: 9848469
>cout<<(long &)num;

At this point, you are calling the function that handles the overloaded << operator, and C++ passes values to functions by pushing them onto the stack, then calling the function.  The 10 comes from your earlier declaration of num.

>(int &)num=10;

Minor point of clarity, pretty sure you already have this, but: 0Ah = 0x0A = 0A hexadecimal = 10 decimal.
0
 

Author Comment

by:TKD
ID: 9848502
const int num = 20;
(int &)num=10;
cout<<(long &)num;
cout<<(int &)num;
cout<<num;

if the output of "cout<<(long &)num;" is 10,
why isn't the ouput 10 of cout<<(int &)num; and cout<<num ?
Does num have memory in compile-time???
????
0
 
LVL 1

Expert Comment

by:Gratch06
ID: 9848599
Having obviously misunderstood the depth of the question the first time, I'll go again from a different angle.

Adjusted code, making all types explicit and giving explanation for each step.
>const int num = 20;   //declare a constant integer named 'num' and give it the value of 20
>(int &)num=10;         //change the address of num to 10
>cout<<(long &)num; //print out the address of num, if it were a long
>cout<<(int &)num;    //print out the address of num, if it were an int
>cout<<(const int)num; //print out the value of num

Changing the final line to cout<<(const int&)num prints out 10, just as would be expected.

My only problem is on the final instruction...if we're changing the address of num in step 2, why would it copy the value of 20?  Wouldn't this variable be theoretically garbage?
0
 
LVL 19

Expert Comment

by:Dexstar
ID: 9848616
@Gratch06:

We should have made this clear before...  This question is kind of a continuation of this question:
http://www.experts-exchange.com/Programming/Programming_Languages/Cplusplus/Q_20811368.html

Where we established that "num", because it is a const, doesn't have any memory addresses.  The compiler explicitly uses 0Ah wherever we used num (almost like a #define).

The problem is, it explicitly uses the value 14h for the first call, and then 0Ah for the rest of the calls.  That's what we're trying to figure out.

Dex*
0
 
LVL 12

Expert Comment

by:andrewjb
ID: 9849159
Interestingly, Borland C++ Builder gives an output of 10, 10 , 20...

0
 
LVL 4

Expert Comment

by:PhilipNicoletti
ID: 9850733
From The ISO C++ Standard, Section 7.1.5.1 The cv-qualifiers :

4 Except that any class member declared mutable (7.1.1) can be modfied, any
attempt to modify a const object during its lifetime (3.8) results in undefined
behavior.

So you can not predict what the results will be. Different compilers can give
different results. Different versions of the same compiler can give different
results. Different compiler options on the same compiler can give
different results.
0
 

Expert Comment

by:Icykorpio
ID: 9850769
nope...

NUM does take an entry in the symbol table with the attribute as CONST during the lexcial analynizing process...and the compiler simply takes it out and fills it there...that's all~

Regards
Icykorpio

0
 

Expert Comment

by:Icykorpio
ID: 9850858
sorry... I miss some lines of the question...
0
 

Expert Comment

by:Icykorpio
ID: 9850899
The problem is, it explicitly uses the value 14h for the first call, and then 0Ah for the rest of the calls.  That's what we're trying to figure out.
==========================================

this is reasonable...when no type cast...compiler takes the const directly from the symbol table, so 14h...other wise(as here to a long) from the memory...then 0Ah...
0
 

Expert Comment

by:Icykorpio
ID: 9850919
it is 0A for the first call and 14h for the rest calls...
0
 

Expert Comment

by:Icykorpio
ID: 9850946
standards is standards but every specific implementation does have its own defined way
0
 
LVL 19

Expert Comment

by:Dexstar
ID: 9850967
Yeah, we see WHAT is going on, and we know the behaviour is undefined...  We just want to know WHY the compiler is using 10 for the first call and 20 for the other 2.

Dex*
0
How to run any project with ease

Manage projects of all sizes how you want. Great for personal to-do lists, project milestones, team priorities and launch plans.
- Combine task lists, docs, spreadsheets, and chat in one
- View and edit from mobile/offline
- Cut down on emails

 
LVL 17

Expert Comment

by:rstaveley
ID: 9851095
const isn't as "straight-talking" as #define. It looks like the third cout is treating num as a #define and the previous couts are not.
0
 
LVL 17

Expert Comment

by:rstaveley
ID: 9851169
...you get 101020 on GCC3.2 and 102020 on VC7.1 - different undefined interpretations, I guess.
0
 

Expert Comment

by:Icykorpio
ID: 9859122
I have said why
0
 
LVL 19

Expert Comment

by:Dexstar
ID: 9859422
I still don't understand why it uses 20 for the first call and 10 for the other 2.  How is it picking which one to use when?

Dex*
0
 
LVL 12

Expert Comment

by:andrewjb
ID: 9859565
Does it actually matter? You're doing something that's naughty and undefined, so don't do it. Apart from the achademic interest of why it does this, is there another reason you're interested?

It probably depends what day of the week it was when the compiler writers coded this :-)

0
 
LVL 19

Expert Comment

by:Dexstar
ID: 9859823
No, it doesn't actually matter, but yes, I still want to know for purely pedantic reasons.

Dex*
0
 
LVL 17

Expert Comment

by:rstaveley
ID: 9860170
Looking at the .asm generated by VC7.1, you see:
--------8<--------
; Line 7
      mov      DWORD PTR _num$[ebp], 20            ; 00000014H
; Line 8
      mov      DWORD PTR _num$[ebp], 10            ; 0000000aH
; Line 9
      mov      eax, DWORD PTR _num$[ebp]
      push      eax
      mov      ecx, OFFSET FLAT:?cout@std@@3V?$basic_ostream@DU?$char_traits@D@std@@@1@A
      call      ??6?$basic_ostream@DU?$char_traits@D@std@@@std@@QAEAAV01@J@Z ; std::basic_ostream<char,std::char_traits<char> >::operator<<
; Line 10
      push      20                              ; 00000014H
      mov      ecx, OFFSET FLAT:?cout@std@@3V?$basic_ostream@DU?$char_traits@D@std@@@1@A
      call      ??6?$basic_ostream@DU?$char_traits@D@std@@@std@@QAEAAV01@H@Z ; std::basic_ostream<char,std::char_traits<char> >::operator<<
; Line 11
      push      20                              ; 00000014H
      mov      ecx, OFFSET FLAT:?cout@std@@3V?$basic_ostream@DU?$char_traits@D@std@@@1@A
      call      ??6?$basic_ostream@DU?$char_traits@D@std@@@std@@QAEAAV01@H@Z ; std::basic_ostream<char,std::char_traits<char> >::operator<<
--------8<--------
In VC7.1, the "constant" 20 is saved on the stack and then overwritten by 10. That value is then using for the cout - see line 9.  Subsequent couts push immediates (20), which is what you'd expect fom a #define'd constant. The outcome is similar to TKD's, but it is interesting to see that it isn't using an immediate for the 10, where TKD's compiler does push an immediate.

Like Dexstar, I find this interesting, because it shines some light on the oddness of const in C++ in compiler implementations. C's #define is much more transparent than C++'s const. A C++ const may be an immediate or something in the data segment (or 'CONST' segment)... or in this case, the stack.
0
 
LVL 19

Expert Comment

by:Dexstar
ID: 9860186
@rsastevely:  Turn on optimizations for your compiler, and you'll get something more like what I posted above (I'm also using VC 7.1).  D*
0
 
LVL 17

Expert Comment

by:rstaveley
ID: 9860416
You're right, Dextar.

The unoptimised disassembly sheds some light on the method behind the madness :-)

It is a similar story for GCC3.2 without optimisations:
--------8<--------
        movl    $20, -4(%ebp)
        movl    $10, -4(%ebp)
        subl    $8, %esp
        pushl   -4(%ebp)
        pushl   $_ZSt4cout
.LCFI3:
        call    _ZNSolsEl
        addl    $16, %esp
        subl    $8, %esp
        pushl   -4(%ebp)
        pushl   $_ZSt4cout
        call    _ZNSolsEi
        addl    $16, %esp
        subl    $8, %esp
        pushl   $20
        pushl   $_ZSt4cout
        call    _ZNSolsEi
--------8<--------

Except that the 10 value is taken from the stack for cout<<(int &)num as well as cout<<(long &)num.

Interesting to see that unoptimised GCC pushes directly from the stack

    pushl -4(%ebp)

...and VC7.1 uses EAX as an intermediary - i.e. the equivalent of...

   movl    -4(%ebp),eax
   pushl   eax

When GCC is optimised (-O3), it pushes immediates just like VC.
0
 
LVL 19

Accepted Solution

by:
Dexstar earned 100 total points
ID: 9860530
@rstaveley:  This question has kinda been moved here:
http://www.experts-exchange.com/Programming/Programming_Languages/Assembly/Q_20812395.html

Look at my last post where I tried it with a bunch of different type of casts.  Sometimes it uses 10, and sometimes is ues 20.

Dex*
0
 
LVL 19

Expert Comment

by:Dexstar
ID: 9875675
@TKD:  Have you gotten a satisfactory answer to this question?  I know I have.  I'm going to close out the other question, but I'm not sure how you want to handle this one.
0
 

Author Comment

by:TKD
ID: 9882669
Yes. I get the answer from
http://www.experts-exchange.com/Programming/Programming_Languages/Assembly/Q_20812395.html
Thanks for ur discuss and helps!!
I learn a lot!
THX.

0
 
LVL 17

Expert Comment

by:rstaveley
ID: 9883007
It has been an interesting diversion. It beats doing real work :-)
0
 
LVL 19

Expert Comment

by:Dexstar
ID: 9883033
Yeah, I especially appreciate the posting of the code generated by gcc.  I don't use that compiler at all, so I would not have been able to see that otherwise.

Dex*
0

Featured Post

Do You Know the 4 Main Threat Actor Types?

Do you know the main threat actor types? Most attackers fall into one of four categories, each with their own favored tactics, techniques, and procedures.

Join & Write a Comment

When writing generic code, using template meta-programming techniques, it is sometimes useful to know if a type is convertible to another type. A good example of when this might be is if you are writing diagnostic instrumentation for code to generat…
Introduction This article is a continuation of the C/C++ Visual Studio Express debugger series. Part 1 provided a quick start guide in using the debugger. Part 2 focused on additional topics in breakpoints. As your assignments become a little more …
The goal of the tutorial is to teach the user how to use functions in C++. The video will cover how to define functions, how to call functions and how to create functions prototypes. Microsoft Visual C++ 2010 Express will be used as a text editor an…
The viewer will learn how to pass data into a function in C++. This is one step further in using functions. Instead of only printing text onto the console, the function will be able to perform calculations with argumentents given by the user.

708 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question

Need Help in Real-Time?

Connect with top rated Experts

13 Experts available now in Live!

Get 1:1 Help Now