#1
  1. No Profile Picture
    Registered User
    Devshed Newbie (0 - 499 posts)

    Join Date
    Jun 2013
    Posts
    4
    Rep Power
    0

    Output explanation required.Not able to follow


    I am not able to understand the output generated by the compiler in the below mentioned program:- :confused:
    #include<stdio.h>
    #define PRODUCT(x) (x*x)
    int main()
    {
    int i=3,j,k,l;
    j=PRODUCT(i+1);
    k=PRODUCT(i++);
    l=PRODUCT(++i);
    printf("%d %d %d %d\n",i,j,k,l);
    return 0;
    }


    :flame:
  2. #2
  3. Contributing User
    Devshed Supreme Being (6500+ posts)

    Join Date
    Jan 2003
    Location
    USA
    Posts
    7,173
    Rep Power
    2222
    What output?

    What did you expect?

    What did you get?

    Why are you trying to write bad code on purpose?

    Try this little exercise:
    Expand the PRODUCT macros in each of the three assignment statements in order to see what source code they create.

    For example, PRODUCT(i+1) creates i+1*i+1, which for i= 3 does produce the result of 7. Were you expecting 16? Why would you have expected that?

    In the other two, you are modifying i within the same expression, which is a quaranteed disaster because that's undefined behavior, so the language does not define how the compiler should handle it.
  4. #3
  5. No Profile Picture
    Registered User
    Devshed Newbie (0 - 499 posts)

    Join Date
    Jun 2013
    Posts
    4
    Rep Power
    0
    The output I am getting in my compiler is 7,7,9 and 49.
    I do not understand how. what will be the value of i,j,k and l.
    How did u get 7...?
    Sir, i am just a beginner. detailed explanation would be appreciated
  6. #4
  7. Contributing User
    Devshed Supreme Being (6500+ posts)

    Join Date
    Jan 2003
    Location
    USA
    Posts
    7,173
    Rep Power
    2222
    And you still have not told us what output you expected! Why do you continue to withhold vital information from us? Don't you want any help?

    That PRODUCT you #define'd is a macro. When you build an executable, your integrated development environment (IDE, what you probably call a "compiler" even though the compiler is only one small part of it) first runs the pre-processor. The pre-processor inserts the files you name in the #include statements and expands all macros.

    Macro expansion is where the reference to the macro is replaced in the source code with what the macro is defined as being. In the case of PRODUCT, it also inserts the expression that you pass to PRODUCT.

    Now look at the j-assignment:
    j=PRODUCT(i+1);
    That would expand to exactly what I already told you it would expand to:
    j=i+1*i+1;
    Now please evaluate that. Remember that you do multiplication before you do addition. So, substituting in the value of i, which is 3:
    j = 3 + 1*3 + 1;
    1*3 is 3. 3 + 3 + 1 is 7. So the value of 7 is assigned to j. Pure and simple.

    Now for the i++ and the ++i examples, please read this page I wrote about a similar problem that was presented in our Java class: Evaluating (x + x * ++x).

    Now, is your homework assignment to figure out how write a macro that will work? Or is it for you to explain why really bad code is really bad code?

    PS
    I ran gcc to only do the pre-processing. This is what it expanded your source code to (excluding the long inclusion of stdio.h):
    Code:
    int main()
    {
        int i=3,j,k,l;
        
        j= ( i+1 * i+1 ) ;
        k= ( i++ * i++ ) ;
        l= ( ++i * ++i ) ;
        
        printf("%d %d %d %d\n",i,j,k,l);
        return 0;
    }
    Please note that it agrees with my expansion of the j assignment statement.

    You still need to tell us what you think the final values of i, k and l should be.

    Comments on this post

    • Winters agrees : :D
    Last edited by dwise1_aol; June 3rd, 2013 at 12:29 PM.
  8. #5
  9. No Profile Picture
    Registered User
    Devshed Newbie (0 - 499 posts)

    Join Date
    Jun 2013
    Posts
    4
    Rep Power
    0
    well i expected the output to be---
    i=3
    j=16
    k=9
    l=16
  10. #6
  11. No Profile Picture
    Registered User
    Devshed Newbie (0 - 499 posts)

    Join Date
    Jun 2013
    Posts
    4
    Rep Power
    0
    I forgot that we do multiplication before addition.......!!!
    my mistakes are amazing:/

    and i am going through your page for-->Evaluating (x + x * ++x)
    thanks a ton
  12. #7
  13. Contributing User
    Devshed Supreme Being (6500+ posts)

    Join Date
    Jan 2003
    Location
    USA
    Posts
    7,173
    Rep Power
    2222
    Originally Posted by VishalJain67
    well i expected the output to be---
    i=3
    j=16
    k=9
    l=16
    I understand why you think j should be 16. I hope you are realizing why it's not and I hope you are thinking of how to change the PRODUCT macro to correct that. Think parentheses (I cannot give you the answer, but I can try to lead you to realizing it).

    The value you expect for k makes sense.

    I cannot understand why you expect l to be 16. i started out as 3 but then you have incremented it three or four times before using it to calculate l. I would have expected you to think that it would be 42 (6 * 7), whereas the way that the compiler interpreted that probably turned out to be 49 (7*7) -- that all depends on the internals.

    Could you please explain your expectations? Out of curiosity.
  14. #8
  15. Contributing User
    Devshed Supreme Being (6500+ posts)

    Join Date
    Jan 2003
    Location
    USA
    Posts
    7,173
    Rep Power
    2222
    Originally Posted by VishalJain67
    I forgot that we do multiplication before addition.......!!!
    my mistakes are amazing:/
    Order of precedence! That is an extremely important concept to learn in programming. Some operators in C has higher precedence over others, so they will be performed before others. It is extremely important that you learn how all the operators rank with others. Of course, you can always use parentheses to override the natural precedence (HINT HINT for your PRODUCT(i+1) situation), but when somebody has written an expression depending on natural precedence, then you need to understand that natural precedence in order to understand that expression.

    Seriously, learn the order of precedence and always keep a copy of it handy at all times. My boss, who I think has a PhD, used to teach a class in C programming and at the start of every course he would visit me to make a copy of the order of precedence from one on my reference books. It is that important!

    On another note, I had been programming in Pascal for 10 years before I started working with C and C++. Pascal's order of precedence for AND and OR with relation to relational operators (eg, <>, >, <) in conditional expressions was not what it should have been, so you always had to use parentheses to make everything right. In any language you work with, you need to know its own particular order of precedence for its operators.

    Originally Posted by VishalJain67
    and i am going through your page for-->Evaluating (x + x * ++x)
    thanks a ton
    One of the things you should get out of that page is that when you are dealing with undefined behavior then everything depends on the code that the compiler generates.

    Which immediately goes over your experience. All digital computers have their own instruction set, a set of instructions that they can perform. These instructions are usually simple single operations like moving data, adding, subtracting, testing, etc. There is a form of programming called assembly in which every single line is a single instruction which corresponds directly with a single instruction in the computer's instruction set.

    The situation is that what the compiler does is to translate your C source code into the assembly instructions that will do what the C source says to do. So when you ask your program to do something that is not defined by the C language standard (such as post- and/or pre-incrementing/decrementing the same variable more than once in the same expression, which is what you are doing for k and l), then the only way to know that your program is doing would be to read the assembly code that it generates.

    Most compilers have options to save an assembly code listing of the program. But as my page should have informed you, each compiler could create something different that would do something different. The purpose of having a language standard is so that we will always have consistent results regardless of what computer or compiler we're using. The problems arise when we try to do something that the standard does not define. One forum member here has a signature tag that describes using undefined behavior as being like dancing barefoot on broken glass.

    With MinGW gcc on Windows 7, I compiled your code first to only run the pre-processor, which expands the macros, and then to generate an assembly listing. Please bear with me here.

    Here is the preprocessor output of part of your program (most of it is the inclusion of the stdio.h header file):
    Code:
    int main()
    {
        int i=3,j,k,l;
        
        j= ( i+1 * i+1 ) ;
        k= ( i++ * i++ ) ;
        l= ( ++i * ++i ) ;
        
        printf("%d %d %d %d\n",i,j,k,l);
        return 0;
    }
    I already produced this earlier.

    Now here is the assembly listing. I have taken the liberty to comment it heavily in order to make it more understandable:
    Code:
    	.file	"vishal.c"
    gcc2_compiled.:
    ___gnu_compiled_c:
    	.def	___main;	.scl	2;	.type	32;	.endef
    .text
    LC0:
    	.ascii "%d %d %d %d\12\0"
    	.align 4
    .globl _main
    	.def	_main;	.scl	2;	.type	32;	.endef
    _main:
    	pushl %ebp
    	movl %esp,%ebp
    	subl $24,%esp
        #  Local variables:
        #       i : -4(%ebp)
        #       j : -8(%ebp)
        #       k : -12(%ebp)
        #       l : -16(%ebp)
    	call ___main
    	movl $3,-4(%ebp)       # i = 3;
        
        #   j = i + 1 * i + 1;
        #       multiplication by 1 optimized out
        #       leaving expression effectively i + i + 1
    	movl -4(%ebp),%eax     # load i in EAX; EAX = 3
    	movl -4(%ebp),%edx     # load i in EDX; EDX = 3
    	addl %edx,%eax         # add EAX and EDX; EAX = 3+3 = 6
    	leal 1(%eax),%edx      # add 1 and store in EDX; EDX = 6 + 1 = 7
    	movl %edx,-8(%ebp)     # store EDX in j; j = 7
        
        #   k = i++ * i++;
    	movl -4(%ebp),%eax     # load i in EAX; EAX = 3
    	imull -4(%ebp),%eax    # mult EAX by i; EAX = 9
    	movl %eax,-12(%ebp)    # store EAX in k; k = 9
    	incl -4(%ebp)          # first post-increment; i contains 4
    	incl -4(%ebp)          # second post-increment; i contains 5
        
        #   l = ++i * ++i;
    	incl -4(%ebp)          # first pre-increment; i contains 6
    	incl -4(%ebp)          # second pre-increment; i contains 7
    	movl -4(%ebp),%eax     # load i in EAX; EAX = 7
    	imull -4(%ebp),%eax    # mult EAX by i; EAX = 7 * 7 = 49
    	movl %eax,-16(%ebp)    # store in l; l = 49
        
        #   printf("%d %d %d %d\n",i,j,k,l);
    	addl $-12,%esp
    	movl -16(%ebp),%eax
    	pushl %eax             # pass l
    	movl -12(%ebp),%eax
    	pushl %eax             # pass k
    	movl -8(%ebp),%eax
    	pushl %eax             # pass j
    	movl -4(%ebp),%eax
    	pushl %eax             # pass i
    	pushl $LC0             # pass format string
    	call _printf           # call printf
        
        #   return 0;
    	addl $32,%esp
    	xorl %eax,%eax
    	jmp L4
    	.align 4
    L4:
    	leave
    	ret
    	.def	_printf;	.scl	2;	.type	32;	.endef
    The comments will inform you of what's happening to the value of i throughout this particular compilation of your program. A different compiler could have handled parts of it differently, as you should have learned from that my page.

    For example, when we calculate the value for l, my program does what I think yours does too: it pre-increments i both times and changes its contents in memory before even beginning to attempting to calculate the product of those two values. As a result, i, which started out being 5, gets incremented twice to become 7 for both references to i in the multiplication, resulting in a result of 49, 7 squared. But if our C compiler were on a different computer platform where all calculations are performed on a stack (as in the case of Java and JavaScript on my page), then i's value of 5 would have been pre-incremented to six and pushed onto the stack, then i's value of 6 would have been pre-incremented to 7 and pushed onto the stack, after which both values would have been popped off the stack and multiplied to provide us the result of 42, not 49.

    There is a very important term that occurs in the C standard, but which I was unaware of when I wrote that web page: sequence point. Read and understand what it says. Unfortunately, the Wikipedia article is only translated into three other languages, all of them Slavic (Russian, Ukrainian, and I'm not quite sure what). The important thing for you to learn from sequence points is that there are points in your code where all the side-effects of your previous operations have been completed and can no longer have unexpected effects on what you're doing.
  16. #9
  17. No Profile Picture
    Registered User
    Devshed Newbie (0 - 499 posts)

    Join Date
    May 2013
    Posts
    15
    Rep Power
    0
    Hi Vishal,

    Define your macro as

    #define PRODUCT(x) ((x)*(x))

    then you get the expected answer

    if defining the macro as #define PRODUCT(x) (x*x)
    as dwise1_aol told your program just made the compiler understand logic in different way
  18. #10
  19. Contributed User
    Devshed Specialist (4000 - 4499 posts)

    Join Date
    Jun 2005
    Posts
    4,392
    Rep Power
    1871
    > #define PRODUCT(x) ((x)*(x))
    This is good only in so far that it makes well-defined expressions consistent.
    Like for example
    PRODUCT(x+1);

    However, it does nothing to help with PRODUCT(x++), because the whole thing is in undefined behaviour territory (as mentioned several times already, but all the newbies seem to be ignoring).

    Same code, different compilers, different answers
    Trying to pick apart what PRODUCT(x++) is a waste of time. You can't use what you learn in any other circumstance. Hell, some compilers will give you different answers just by changing the optimisation settings (or upgrading your compiler). You do NOT want to be writing code which is that sensitive to changing environment. It isn't that the compiler is broken, it's the CODE which is broken.

    @OP, I suggest you show your tutor my test results, if they insist that such code is worthy of analysis (or capable of producing a consistent answer). You might well want to find another tutor if they don't relent.
    If you dance barefoot on the broken glass of undefined behaviour, you've got to expect the occasional cut.
    If at first you don't succeed, try writing your phone number on the exam paper

IMN logo majestic logo threadwatch logo seochat tools logo