This discussion has been locked.
You can no longer post new replies to this discussion. If you have a question you can start a new discussion

Why Keil generates differen outputs from the other compilers with the same code?

I am using the following code in different compiler:

#include <stdio.h>

int main(void)
{
  int i = 0;
  int b[10] = {100,101,102,103,104,105,106,107,108,109};
  int c[10] = {0,1,2,3,4,5,6,7,8,9};

  b[i + 0] = c[i++ % 100];
  b[i + 0] = c[i++ % 100];
  b[i + 0] = c[i++ % 100];
  b[i + 0] = c[i++ % 100];
  b[i + 0] = c[i++ % 100];
  b[i + 0] = c[i++ % 100];

  for(i = 0; i < 10; i++)
     printf("b[%d] = %d\n",i,b[i]);
  return 0;
}

But I am getting different output by using Keil,
the output as follows:

//Keils output... uVision3 V3.53, compiler Armcc.exe
b[0] = 100
b[1] = 0
b[2] = 1
b[3] = 2
b[4] = 3
b[5] = 4
b[6] = 5
b[7] = 107
b[8] = 108
b[9] = 109

//Microsoft Visual STD 6.0 output
b[0] = 0
b[1] = 1
b[2] = 2
b[3] = 3
b[4] = 4
b[5] = 5
b[6] = 106
b[7] = 107
b[8] = 108
b[9] = 109
Press any key to continue



//Microsoft Visual STD 2005 output
b[0] = 0
b[1] = 1
b[2] = 2
b[3] = 3
b[4] = 4
b[5] = 5
b[6] = 106
b[7] = 107
b[8] = 108
b[9] = 109
Press any key to continue

//Borland C++Builder6.0 output....
b[0] = 0
b[1] = 1
b[2] = 2
b[3] = 3
b[4] = 4
b[5] = 5
b[6] = 106
b[7] = 107
b[8] = 108
b[9] = 109

Could you tell me something about this problem?

Parents
  • Could you tell me something about this problem?

    There is no problem. The behavior of statements like

    a[i] = i++:
    

    is implementation-defined in C (see K&R, chapter "Precedence and Order of Evaluation". It contains this example). Different compilers are free to evaluate the left or the right side of the assignment first.

    It is up to the programmer to deal with the consequences.

Reply
  • Could you tell me something about this problem?

    There is no problem. The behavior of statements like

    a[i] = i++:
    

    is implementation-defined in C (see K&R, chapter "Precedence and Order of Evaluation". It contains this example). Different compilers are free to evaluate the left or the right side of the assignment first.

    It is up to the programmer to deal with the consequences.

Children
  • Even when the behaviour is clearly defined, there is absolutely no requirement whatsoever for the compiler to generate any specific set of machine instructions.

    In fact, you should expect different compilers to generate different sets of machine instructions!

    Even different versions of the same compiler can generate different sets of machine instructions - which is why it is never trivial to upgrade the compiler part-way through a project.

    And, of course, changing options can cause the same version of the same compiler to generate different sets of machine instructions!

    This is why you really must not write timing loops in any high-level language - see: www.8052.com/.../98544
    and: www.8052.com/.../150987
    etc,...

  • Thank you for your reply.

    In visual STD the following code:

    int main(void)
    {
      int i = 0;
      int b[10] = {100,101,102,103,104,105,106,107,108,109};
      int c[10] = {0,1,2,3,4,5,6,7,8,9};
    
      b[i++ + 0] = c[i % 100];
      b[i++ + 0] = c[i % 100];
      b[i++ + 0] = c[i % 100];
      b[i++ + 0] = c[i % 100];
      b[i++ + 0] = c[i % 100];
      b[i++ + 0] = c[i % 100];
    
      for(i = 0; i < 10; i++)
         printf("b[%d] = %d\n",i,b[i]);
      return 0;
    }
    

    generates the following output(there is no difference):

    b[0] = 0
    b[1] = 1
    b[2] = 2
    b[3] = 3
    b[4] = 4
    b[5] = 5
    b[6] = 106
    b[7] = 107
    b[8] = 108
    b[9] = 109
    

    And the following code:

    int main(void)
    {
      int i = 0;
      int b[10] = {100,101,102,103,104,105,106,107,108,109};
      int c[10] = {0,1,2,3,4,5,6,7,8,9};
    
      b[i++ + 0] = c[i++ % 100];
      b[i++ + 0] = c[i % 100];
      b[i++ + 0] = c[i % 100];
      b[i++ + 0] = c[i % 100];
      b[i++ + 0] = c[i % 100];
      b[i++ + 0] = c[i % 100];
    
      for(i = 0; i < 10; i++)
         printf("b[%d] = %d\n",i,b[i]);
      return 0;
    }
    


    Generates the following output:

    b[0] = 0
    b[1] = 101
    b[2] = 2
    b[3] = 3
    b[4] = 4
    b[5] = 5
    b[6] = 6
    b[7] = 107
    b[8] = 108
    b[9] = 109
    

    With a visual studio background, I think or hope that would be the same in keil.

  • With a visual studio background, I think or hope that would be the same in keil.

    No - you need a standard C background, and this would tell you that you cannot expect any particular order in which the left and the right side of a statement are evaluated. This also means that side effects of the statements may occur in either order. If you require a certain order even across different compilers, you will need to change the code accordingly.

  • Compilers don't work to arbitrary user's thoughts and hopes - they work to their published specifications, which will be based on appropriate standards.

  • Even when/if standards do specify exact order of evaluation, a developer should make sure that a reasonably skilled reader will understand the code.

    It is easy to understand precedence rules for + in relation to *, but when expressions gets complex, extra parentheses should be added.

    And expressions with side effects should really not be accepted, if the evaluation order and side effect may interfere. Just do not - ever - write code where you use ++ or -- on a variable and use the variable somewhere else in the same statement.

    And do not write code where the address of the same variable is taken twice as parameters to a function call. The function will probably expect that there are no aliasing between the two pointers.

    And do not try to write code that accesses a global variable both directly and through a pointer.

  • Thank you for your important advices.

  • Having said that, it does seem the Keil is a little bit out on it's own here. I just tried GCC and it works the same as the others.

    Does add a rather tricky portability issue.

  • Does add a rather tricky portability issue.

    Actually it doesn't. The issue here is not portability but outright incorrecness of the code. Code along the lines of

    a[i]=i++;
    

    doesn't just yield an implementation-defined result, like some earlier respondents stated. It causes undefined behaviour --- which means no matter how unspeakably bizarre this code behaves, that's precisely correct.

    You guys are ultimately discussing the wrong question here. You should worry about repairing the code, not about what compilers might make of it in its current, buggy state. It makes no sense whatsoever to discuss particular results of running this code on any compiler. It's impossible for any compiler to get this wrong.

  • It causes undefined behaviour --- which means no matter how unspeakably bizarre this code behaves, that's precisely correct.

    My copy of K&R seems to disagree with that. It states that the order in which the operands of an operator (in this case: the assignment operator =) are evaluated is left to the compiler.

    And in this case, the compiler has only two options - evaluate the left-hand operand first, or evaluate the right-hand argument first. Any behavior that's more bizarre than that would point to a faulty compiler. The compiler may not produce code that omits the statement, enters an endless loop, or exits the program, for example.

    Of course, an evil-yet-standard-compliant compiler could flip a coin to determine the order of evaluation for every multi-operand operator it encounters. At least I didn't see anything about always having to chose the same order.

  • It causes undefined behaviour --- which means no matter how unspeakably bizarre this code behaves, that's precisely correct.

    ...

    My copy of K&R seems to disagree with that. It states that the order in which the operands of an operator (in this case: the assignment operator =) are evaluated is left to the compiler.

    That doesn't constitute a disagreement. The problem is that 'i' is being modified more than once between sequence points which invokes undefined behaviour. Once that has happened all bets are off.

    And in this case, the compiler has only two options - evaluate the left-hand operand first, or evaluate the right-hand argument first. Any behavior that's more bizarre than that would point to a faulty compiler. The compiler may not produce code that omits the statement, enters an endless loop, or exits the program, for example.

    Every aspect of that paragraph is completely wrong. I suggest that you take a look at the comp.lang.c faq for 'undefined behaviour' and 'order of eveluation'.

  • I suggest that you take a look at the comp.lang.c faq for 'undefined behaviour' and 'order of eveluation'.

    Interesting. The FAQ even mentions the discrepance between K&R (whose wording suggests that the behavior is unspecified) and the C standard (which states that the behavior is indeed undefined).

    Advice taken, I'll make an appropriate note in my K&R.

  • "The problem is that 'i' is being modified more than once between sequence points which invokes undefined behaviour."

    Note that a variable doesn't need to be modified multiple times between sequence points. In this case the user modified the value once, but combined the modification with a second use of the variable.

  • Note that a variable doesn't need to be modified multiple times between sequence points. In this case the user modified the value once, but combined the modification with a second use of the variable.

    Yes, that's what I should have said...