Thread: New to C - Short circuit question

  1. #1
    Registered User
    Join Date
    Sep 2013
    Posts
    4

    New to C - Short circuit question

    Code:
    #include <stdio.h>
    
    int main(void){
      int i, j, k;
      i = 1;
      j = 1;
      k = 1;
      printf("%d\n",++i || ++j && ++k); 
      printf("%d %d %d\n", i, j, k );
    }
    I am working my way through Kn King's C programming book and am stuck on the example above. When I run the code I get:
    1
    2, 1, 1

    I was expecting:

    1
    2, 2, 2

    My thinking is the && has higher precedence than || and will be evaluated first and thus both j and k will be incremented. Then the || clause will be evaluated from and i will be incremented. I guess I am not quite understanding how short circuiting is being applied.... Any help is appreciated!

  2. #2
    - - - - - - - - oogabooga's Avatar
    Join Date
    Jan 2008
    Posts
    2,808
    Order of precedence is entirely separate from short-circuit evaluation. If i (after the increment) is non-zero, then the logical-or is true no matter what ++j and ++k are. So only ++i occurs.

    BTW, you're missing the "return 0" at the end of main.

    The assembly code of the following tells the story:
    Code:
    #include <stdio.h>
    
    int main(void) {
        int i = 1, j = 1, k = 1;
        int n = ++i || (++j && ++k);
        printf("%d: %d, %d, %d\n", n, i, j, k);
        return 0;
    }
    
    // Some of the assembly code for the above:
    
    // i = 1;
      401342:    c7 44 24 24 01 00 00     movl   $0x1,0x24(%esp)
      401349:    00 
    
    // j = 1;
      40134a:    c7 44 24 2c 01 00 00     movl   $0x1,0x2c(%esp)
      401351:    00 
    
    // k = 1;
      401352:    c7 44 24 28 01 00 00     movl   $0x1,0x28(%esp)
      401359:    00 
    
    // ++i;
      40135a:    ff 44 24 24              incl   0x24(%esp)
    
    // if (i != 0) goto SET_N_TO_1; // jump to the end if i is non-zero
      40135e:    83 7c 24 24 00           cmpl   $0x0,0x24(%esp)
      401363:    75 16                    jne    40137b <_main+0x47>
    
    // ++j;
      401365:    ff 44 24 2c              incl   0x2c(%esp)
    
    // if (j == 0) goto SET_N_TO_0;
      401369:    83 7c 24 2c 00           cmpl   $0x0,0x2c(%esp)
      40136e:    74 12                    je     401382 <_main+0x4e>
    
    // ++k;
      401370:    ff 44 24 28              incl   0x28(%esp)
    
    // if (k == 0) goto SET_N_TO_0;
      401374:    83 7c 24 28 00           cmpl   $0x0,0x28(%esp)
      401379:    74 07                    je     401382 <_main+0x4e>
    
    // SET_N_TO_1:
      40137b:    b8 01 00 00 00           mov    $0x1,%eax
      401380:    eb 05                    jmp    401387 <_main+0x53>
    
    // SET_N_TO_0:
      401382:    b8 00 00 00 00           mov    $0x0,%eax
      401387:    89 44 24 20              mov    %eax,0x20(%esp)
    The cost of software maintenance increases with the square of the programmer's creativity. - Robert D. Bliss

  3. #3
    Registered User
    Join Date
    Jun 2011
    Posts
    4,513
    This is discussed in this thread. Pay special attention to post #7.

  4. #4
    Registered User
    Join Date
    Sep 2013
    Posts
    4
    Thanks for the response. I am not familiar with assembly so unfortunately it does not help in my understanding! I guess I am still lost since I do not understand why j and k do not increment. If I run the following code:
    Code:
    #include <stdio.h>
    
    int main(void){
      int i, j, k;
      i = 1;
      j = 1;
      k = 1;
      printf("%d\n",++j && ++k); 
      printf("%d %d %d\n", i, j, k );
      return 0;
    }
    I get:
    1
    1, 2, 2

    as expected. I do not understand why putting the || first would change this.

  5. #5
    Lurking whiteflags's Avatar
    Join Date
    Apr 2006
    Location
    United States
    Posts
    9,612
    OR stops evaluating once an expression results in truth.

    if ( ++i || ++j ) ...

    There are values for i such that j is never incremented. In fact, nearly all values of i will result in j not being incremented. The exception is when i is initially -1.

  6. #6
    Registered User
    Join Date
    Jun 2011
    Posts
    4,513
    The OP seems to understand short circuit evaluation - it seems this thread is more of a question about operator precedence.

    OP, did you see the link I posted above?

  7. #7
    Registered User
    Join Date
    Sep 2013
    Posts
    4
    I did but did not see your post until after I posted my last response. So basically the compiler knows that j and k are non-zero and thus only evaluates and increments i. I need to try some more code to make sure I understand but that post helped.

  8. #8
    Registered User
    Join Date
    Jun 2011
    Posts
    4,513
    From the thread I linked to, "...precedence determines grouping, not order of evaluation."

    So you can think of:

    Code:
    ++i || ++j && ++k
    ... as:

    Code:
    (++i) || (++j && ++k)
    It is then evaluated from left to right. The left part is true ... so there is no need to evaluate the right part. Therefore, those variables do not change.

    For a bit of extra fun, try what whiteflags mentioned above and run it with 'i' initially -1. I think you can already see what the output will be.

  9. #9
    - - - - - - - - oogabooga's Avatar
    Join Date
    Jan 2008
    Posts
    2,808
    Quote Originally Posted by Matticus View Post
    The OP seems to understand short circuit evaluation - it seems this thread is more of a question about operator precedence.
    My impression is exactly opposite.

    @euclid_mpls,
    I wasn't assuming that you were familiar with assembly language. That would be a pretty stupid assumption. I just assumed you'd be able to look at it carefully with my comments and get something from it. But since you can't, here's a C interpretation of what the given code compiles to (basically just the assembly comments extracted). It shows exactly how short-circuit evaluation works and exactly why j and k are not incremented.

    Here is the original code:
    Code:
    #include <stdio.h>
     
    int main(void) {
        int i = 1, j = 1, k = 1;
        int n = ++i || (++j && ++k);
        printf("%d: %d, %d, %d\n", n, i, j, k);
        return 0;
    }
    Here is the interpretation:
    Code:
    #include <stdio.h>
    
    int main(void) {
        int n, i, j, k;
    
        i = 1;
        j = 1;
        k = 1;
    
        ++i;
        if (i != 0) goto SET_N_TO_1;
    
        ++j;
        if (j == 0) goto SET_N_TO_0;
    
        ++k;
        if (k == 0) goto SET_N_TO_0;
    
    SET_N_TO_1:
        n = 1;
        goto PRINT_RESULTS;
    
    SET_N_TO_0:
        n = 0;
    
    PRINT_RESULTS:
        printf("%d: %d, %d, %d\n", n, i, j, k);
    
        return 0;
    }
    The cost of software maintenance increases with the square of the programmer's creativity. - Robert D. Bliss

  10. #10
    Registered User
    Join Date
    Jun 2011
    Posts
    4,513
    My impression is exactly opposite.
    Ah, I see. I was focused on this part:

    My thinking is the && has higher precedence than || and will be evaluated first...
    And I guess I skimmed over the next:

    ...and thus both j and k will be incremented. Then the || clause will be evaluated from and i will be incremented.
    At least it seems I answered part of their question!

  11. #11
    - - - - - - - - oogabooga's Avatar
    Join Date
    Jan 2008
    Posts
    2,808
    Quote Originally Posted by Matticus View Post
    At least it seems I answered part of their question!
    Tag team!

    I'd say both points needed to be covered. It was probably their interaction that was confusing.

    Considering it from a precedence point-of-view, one might think the && (and the j and k increments) must be computed first, but that's not the case since the value of the && doesn't matter if the LHS of the || is true.

    It's actually pretty confusing and probably a good argument not to put all those increments in there. If you really want your code to do what that code does, it should be spelled out more clearly.
    The cost of software maintenance increases with the square of the programmer's creativity. - Robert D. Bliss

  12. #12
    Registered User
    Join Date
    Sep 2013
    Posts
    4
    Thanks everyone. The initial code was a question in the book but I understand the issue now. If the first OR argument is non-zero the then the statement is non-zero - nothing more needs to be evaluated and thus the short circuit. I was hung up on the precedence of the && and the increments.... Funny how the mind locks onto one thing.....

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. Short circuit evaluation
    By S0undw4ve in forum C Programming
    Replies: 4
    Last Post: 12-09-2012, 05:13 PM
  2. Does C guarantee short circuit evaluation?
    By Syndacate in forum C Programming
    Replies: 10
    Last Post: 08-19-2011, 08:31 PM
  3. a short question
    By peterx in forum C Programming
    Replies: 8
    Last Post: 10-12-2005, 12:45 AM
  4. 'short' question
    By sand_man in forum C Programming
    Replies: 5
    Last Post: 03-20-2005, 05:04 PM
  5. Circuit Boards - probably a dumb question
    By sean in forum A Brief History of Cprogramming.com
    Replies: 1
    Last Post: 10-09-2003, 05:44 PM