1

I'm sorry if it is too conspicuous but I'm a bit obscure here.

I wrote the following code:

#include <stdio.h>
int main() {
    int a = 8 , b = 7 ;
    int temp;
    printf("%d\n", temp=a,a=b,b=temp);
    return 0;
}

It gives a warning with OUTPUT: 0

According to me, The output should have been 8, for I've tried this kind of code printf("%d",a,b); It prints the value of a that leads me to a conclusion that first expression will be printed with a warning of too many arguments for format.
So, In my case when temp=a has to be the answer and hence the value of temp which became 8 should be printed.

Please explain, Where am I going wrong?

Thanks in advance for any help you are able to provide

Vinay Yadav
  • 1,206
  • 1
  • 10
  • 19

5 Answers5

3

From Order of evaluation: [emphasis added]

Order of evaluation of the operands of any C operator, including the order of evaluation of function arguments in a function-call expression, and the order of evaluation of the subexpressions within any expression is unspecified (except where noted below). The compiler will evaluate them in any order, and may choose another order when the same expression is evaluated again.

Since the order of evaluation of function arguments is unspecified. The arguments you are passing to printf() includes both read and write of same variable and there is no sequence point, this will lead to undefined behaviour.

From C Standards#6.5p2

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...


EDIT

In case if you are confused with comma as operator and comma as separator, the comma is a separator in the function argument list.

For reference, quoting an example from C Standards#6.5.17p3

3 EXAMPLE As indicated by the syntax, the comma operator (as described in this subclause) cannot appear in contexts where a comma is used to separate items in a list (such as arguments to functions or lists of initializers). On the other hand, it can be used within a parenthesized expression or within the second expression of a conditional operator in such contexts. In the function call

      f(a, (t=3, t+2), c)

the function has three arguments, the second of which has the value 5.

In the example above:

     Here comma is operator, so the expression will be evaluated to 5 (3+2)
         |
         | 
f(a, (t=3, t+2), c)
   |           |
   |           |
   -------------
        |
   here, comma is separator
H.S.
  • 11,654
  • 2
  • 15
  • 32
  • Sorry for being persistent on this but you said the order of evaluation is unspecified. Is it true for every operator? Like if I write like this (++a)&&(--a)&&(a++). Will this also give undefined behaviour? – Vinay Yadav Aug 16 '20 at 04:02
  • yes but no, `&&` is one of those that force strict sequencing, so side effects of the lhs will be settled before rhs is evaluated, if it is even evaluated... – Antti Haapala -- Слава Україні Aug 16 '20 at 04:19
  • unspecified evaluation is not all, but the fact that they are unsequenced too. – Antti Haapala -- Слава Україні Aug 16 '20 at 04:25
  • 1
    @VinayYadav Check the "Order of evaluation" link provided with answer. In that link, go through the "Ordering" and "Rules" section. – H.S. Aug 16 '20 at 05:55
  • 1
    The title shows the asker believes the assignments are in “comma separated expressions,’ meaning expressions using C’s comma operator (C 2018 6.5.17). They are not, and this answer fails to correct that misbelief or explain why they are not in comma separated expressions. – Eric Postpischil Aug 16 '20 at 10:03
  • @EricPostpischil In the question, OP clearly mentioned - `Comma separated expressions.....`. That means, OP is aware of the fact that comma in argument list is a separator and not operator. I have updated my answer to clarify the same, if there is any confusion. – H.S. Aug 16 '20 at 10:54
2

Your expression

printf("%d\n", temp = a, a = b, b = temp);
//                     ^      ^ argument separator
//             ^^^^^^^^  ^^^^^  ^^^^^^^^ 3 arguments

no comma operator: 3 values to be printed (2 are evaluated but otherwise ignored), one conversion, Undefined Behaviour (unsequenced expressions).

What I think you were looking for

printf("%d\n", (temp = a, a = b, b = temp));
//                      ^      ^ comma operator
//             ^^^^^^^^^^^^^^^^^^^^^^^^^^^ 1 argument grouped

comma operator, 1 value, one conversion, no UB assuming temp is int and temp, b, and a are assignment compatible (which they are in your snippet).

pmg
  • 106,608
  • 13
  • 126
  • 198
2

There is no comma operator in printf("%d\n", temp=a,a=b,b=temp);. In the argument list of a function call, commas separate arguments. They do not represent comma operators.

Thus, in printf("%d\n", temp=a,a=b,b=temp);, there are three separate expressions after the format string: temp=a, a=b, and b=temp.

The C standard does not specify the order in which function arguments, or even parts of function arguments, are evaluated. This causes your code to fall afoul of another rule that says if you both modify and use an object in an unsequenced way, the behavior is not defined by the C standard. For example, a=b uses b, and b=temp modifies b, and these are not sequenced, so the behavior is not defined. While the result is often as if the expressions were evaluated in one order or another, a program with this error may misbehave in other ways.

You can use a comma operator in a function call, but you have to use parentheses to distinguish it from function arguments, as in printf("%d\n", (temp = a, a = b, b = temp));.

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

The answer by H.S. is correct that the order of evaluation of arguments is unspecified in the C-language spec. Arguments can be evaluated in any order.

It is relatively common that the order of evaluation is typically backwards (from the right-most argument to the first argument). This is because of the details of argument ordering on the stack.

We can deduce that the arguments are evaluated this way:

  1. b = temp :: temp is undefined, but likely zero, therefore b is likely zero.
  2. a = b :: If b was zero, then a is now zero.
  3. temp = a :: temp gets assigned the value of a, which was probably zero, but might've been the uninitialized value of temp. This is the argument that printf uses to format %d. The extra arguments are not used (and probably generate a warning)
  4. "%d\n" :: Not much to evaluate here, just a static string.

Although the output could be anything (including nasal demons), this helps explain why the output is frequently 0.

abelenky
  • 63,815
  • 23
  • 109
  • 159
  • The order of evaluation is unspecified, not undefined – M.M Aug 16 '20 at 03:45
  • @abelenky you said the order of evaluation is unspecified/undefined but then U delineated the flow of the program. So, can we do this always like moving from the right-most argument to the first argument? – Vinay Yadav Aug 16 '20 at 04:03
  • this misses the point. the evaluations od arguments are *unsequenced* wrt each other and that, along with modifying and reading the same variable gets us into a trouble. – Antti Haapala -- Слава Україні Aug 16 '20 at 04:23
  • *"It is relatively common that the order of evaluation is typically backwards"* This is correct: The order can be **any** order, but it is *often* backwards. You cannot rely on backwards behavior, but it does help explain the observed result. – abelenky Aug 16 '20 at 14:47
-2

The problem is not initialising temp. The expression " b = temp " Will return an error. To have 8 as the result

printf("%d\n", temp = b, b = a)

You can evaluate the code and just use a single variable inside printf

Edit According to this answer you cannot say the evaluation will be from right to left as it is undefined.

mrBell
  • 41
  • 1
  • 1
  • 4
  • 1
    This still causes undefined behaviour (`b` is written and read without a sequence point) – M.M Aug 16 '20 at 03:36