-4

Can someone please explain why the output here is 2 1 1, what does c prioritise here? how come the output of i++ is 1. Thanks in advance ~

#include <stdio.h>

void main(){
int i=1;
int *p=&i;
printf("%d%d%d\n",*p,i++,i);
}
user4581301
  • 33,082
  • 7
  • 33
  • 54
ProgEnthusiast
  • 59
  • 1
  • 1
  • 5
  • 2
    FYI, `main` always returns `int`. Always. – Thomas Matthews Aug 24 '21 at 00:30
  • Recommendation: When you have a C question don't tag C++. Both languages evolved from the same root, but they look less and less alike every day. – user4581301 Aug 24 '21 at 00:31
  • 1
    My understanding is that this is undefined behavior. The compiler is allowed to evaluate the parameters in any order before passing them to the function. – Thomas Matthews Aug 24 '21 at 00:32
  • To build on what Thomas mentioned, `void main()` has never been a valid signature for `main` in either C or C++, though some compilers do allow it as a nonstandard extension. See [What should main() return in C and C++?](https://stackoverflow.com/q/204476/11082165) – Brian61354270 Aug 24 '21 at 00:33
  • There is no prioritization of the order of parameter evaluation. This allows the compiler to generate faster code by reordering to maximize any advantages. [See this documentation page for more information on similar gotchas](https://en.cppreference.com/w/c/language/eval_order) See the link at the very bottom of that page to see how the rules differ in C++ – user4581301 Aug 24 '21 at 00:34
  • @ThomasMatthews FWIW I think the correct term is unspecified behavior in this case, not undefined behavior. – Brian61354270 Aug 24 '21 at 00:34
  • 4
    On a test you would have to answer "Unspecified". If that's not an option your instructor probably shouldn't be teaching C. – user4581301 Aug 24 '21 at 00:38
  • "what does c prioritise here? " Nothing here. `printf("%d%d%d\n",*p,i++,i);` is bad code. Don't code this way. – chux - Reinstate Monica Aug 24 '21 at 00:38
  • this is a question in a computer science test – ProgEnthusiast Aug 24 '21 at 00:38
  • ProgEnthusiast, `printf("%d%d%d\n",*p,i++,i)` may even cause a bus fault as `i++,i` may happen at the same time. Its UB. – chux - Reinstate Monica Aug 24 '21 at 00:39
  • 1
    Closely related-if not an outright duplicate: [Parameter evaluation order before a function calling in C](https://stackoverflow.com/questions/376278/parameter-evaluation-order-before-a-function-calling-in-c) Second answer is most relevant here. – user4581301 Aug 24 '21 at 00:39
  • 2
    @ProgEnthusiast Since you mentioned that this came up on a test, it may be worth bringing this issue to your instructor's attention. As backing, you can bring up the relevant part of the C99 standard, which would be §6.5.2.2/10. You can get a copy of the standard here: http://www.open-std.org/jtc1/sc22/wg14/www/docs/n1256.pdf. See page 72 for the relevant paragraph, which reads _"The order of evaluation of the function designator, the actual arguments, and subexpressions within the actual arguments is unspecified, but there is a sequence point before the actual call"_. – Brian61354270 Aug 24 '21 at 00:56
  • 1
    I've seen this on written tests in the past as a sort-of booby trap question. I know the instructor knew it was unspecified because he covered it in class. If he hadn't, I'd have called him on it. I'd try to be less of a dick about it these days, mind you. Somewhere along the line I learned it's rude to blurt out "WRONG!" during presentations. – user4581301 Aug 24 '21 at 01:02
  • @Brian: The C standard does not make `void main()` an invalid signature. It makes `int main(void)` and `int main(int argc, char *argv[])` valid in hosted environments and leaves it open whether there are other valid signatures, so a C implementation may define others. In a freestanding environment, the standard does not define what the type of `main` is at all or even whether it is the function called at startup, so an implementation must define it. – Eric Postpischil Aug 24 '21 at 01:05
  • This is a multiple choice test, the choices were: 1) the code won't compile 2) it will display 1 2 1 3) it will display 2 2 1 4) it will display something else. So there isn't actually an answer that says "unspecified". The thing there's 7 other questions that are just like this one. – ProgEnthusiast Aug 24 '21 at 01:05
  • 3
    @ProgEnthusiast: The test is defective. This is a well-known situation in which the behavior is not defined by the C standard. – Eric Postpischil Aug 24 '21 at 01:07
  • Although this example has just one increment operator, it nevertheless is essentially the same as the duplicate. Incrementing `i` and referencing it directly in the argument list is undefined behaviour in its own right; also, referencing it via `*p` just adds another part to the undefined behaviour. Another referenced question is itself deemed a duplicate of the question to which this question is closed as a duplicate. – Jonathan Leffler Aug 24 '21 at 01:09
  • @Brian The correct term in this case is *undefined*. There are no sequence points between the evaluation of the several arguments in a function call. – Steve Summit Aug 24 '21 at 03:03
  • @user4581301 On a test you would want to answer Undefined, if at all possible. – Steve Summit Aug 24 '21 at 03:05
  • @ProgEnthusiast I won't blame you a bit if you don't feel like trying, but there are multiple people here who would back you up if you wanted to lodge a formal complaint with your school's administration about the incompetence of the person setting this test. – Steve Summit Aug 24 '21 at 04:27
  • Even though the question may be flawed, actually enough information is available to determine what happened in this particular case. If the output was `2 1 1`, then clearly the first argument `*p` was processed *last*, because the value was already incremented. That means we can also determine that `i` was processed *first*, otherwise the output would be `2 1 2`. Therefore the arguments were processed right to left. But there is no way to guarantee this always happens. The compiler could have chosen differently. All possible outputs are `1 1 1`, `2 1 1`, `1 1 2`, `2 1 2` and faulty. – Cheatah Aug 24 '21 at 07:24

1 Answers1

4

The behavior of this code is not defined by the C standard per C 2018 6.5 2:

If a side effect on a scalar object is unsequenced relative to either a different side effect on the same scalar object or a value computation using the value of the same scalar object, the behavior is undefined…

i++ has the side effect of updating i with its incremented value. The function call arguments also include *p and i, both of which refer to i and use its value. i is a scalar object. The order of evaluation of function call arguments and their side effects are unsequenced (meaning the C standard does not impose any ordering requirements on them). Therefore, all the conditions for the rule above are met, so the behavior is not defined by the C standard.

Eric Postpischil
  • 195,579
  • 13
  • 168
  • 312