Sequence points and I/O format Specifiers in C - c

The C standard (Annex C) states that there is a sequence point
After the actions associated with each formatted input/output
function conversion specifier.
Given that, why am I getting an unsequenced modification and access to i (clang) warning for the below?
int i = 0;
printf("%d, %d\n", i, ++i);
Based on the standard, there is a sequence point after the first and the second %d. If so I should be getting a 0 1? But then there is no ordering guarantee in the evaluation of function arguments and I could be getting 1 1 instead?
So what does the text of the standard I quoted really mean?

Given that, why am I getting an unsequenced modification and access to
i (clang) warning for the below?
int i = 0;
printf("%d, %d\n", i, ++i);
Because the problem happens when evaluating the function's argument list, before the function is actually called. The evaluations of multiple arguments to the same function call are not sequenced with respect to each other, and you both read and modify i via separate, unsequenced arguments.
The provision you cited is not relevant to this issue. It describes sequence points between the I/O operations performed by the function when it executes. Because function arguments are always passed by value, and because there is a sequence point between evaluating the arguments and executing the function body, I don't see any practical relevance of that provision to the printf-family functions.
For scanf & friends, however, the provision helps ensure that
int i;
scanf("%d, %d", &i, &i);
has well-defined behavior, because it specifies that the two resulting writes to i are sequenced with respect to each other.

Related

Why is the output of the folowing code 543 instead of 345? [duplicate]

In C and C++, is there a fixed order for evaluation of parameter to the function? I mean, what do the standards say? Is it left-to-right or right-to-left?
I am getting confusing information from the books.
Is it necessary that function call should be implemented using stack only? What do the C and C++ standards say about this?
C and C++ are two completely different languages; don't assume the same rules always apply to both. In the case of parameter evaluation order, however:
C99:
6.5.2.2 Function calls
...
10 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.
[Edit]
C11 (draft):
6.5.2.2 Function calls
...
10 There is a sequence point after the evaluations of the function designator and the actual
arguments but before the actual call. Every evaluation in the calling function (including
other function calls) that is not otherwise specifically sequenced before or after the
execution of the body of the called function is indeterminately sequenced with respect to
the execution of the called function.94)
...
94) In other words, function executions do not ‘‘interleave’’ with each other.
C++:
5.2.2 Function call
...
8 The order of evaluation of arguments is unspecified. All side effects of argument expression evaluations take effect
before the function is entered. The order of evaluation of the postfix expression and the argument expression list is
unspecified.
Neither standard mandates the use of the hardware stack for passing function parameters; that's an implementation detail. The C++ standard uses the term "unwinding the stack" to describe calling destructors for automatically created objects on the path from a try block to a throw-expression, but that's it. Most popular architectures do pass parameters via a hardware stack, but it's not universal.
[Edit]
I am getting confusing information from the books.
This is not in the least surprising, since easily 90% of books written about C are simply crap.
While the language standard isn't a great resource for learning either C or C++, it's good to have handy for questions like this. The official™ standards documents cost real money, but there are drafts that are freely available online, and should be good enough for most purposes.
The latest C99 draft (with updates since original publication) is available here. The latest pre-publication C11 draft (which was officially ratified last year) is available here. And a publicly availble draft of the C++ language is available here, although it has an explicit disclaimer that some of the information is incomplete or incorrect.
Keeping it safe: the standard leaves it up to the compiler to determine the order in which arguments are evaluated. So you shouldn't rely on a specific order being kept.
In C/C++ is there a fixed order for evaluation of parameter to the function. I mean what does standards says is it left-to-right or right-to-left . I am getting confusing information from the books.
No, the order of evaluation of function parameters (and of two sub-expressions in any expression) is unspecified behaviour in C and C++. In plain English that means that the left-most parameter could be evaluated first, or it could be the right-most one, and you cannot know which order that applies for a particular compiler.
Example:
static int x = 0;
int* func (int val)
{
x = val;
return &x;
}
void print (int val1, int val2)
{
cout << val1 << " " << val2 << endl;
}
print(*func(1), *func(2));
This code is very bad. It relies of order of evaluation of print's parameters. It will print either "1 1" (right-to-left) or "2 2" (left-to-right) and we cannot know which. The only thing guaranteed by the standard is that both calls to func() are completed before the call to print().
The solution to this is to be aware that the order is unspecified, and write programs that don't rely on the order of evaluation. For example:
int val1 = *func(1);
int val2 = *func(2);
print(val1, val2); // Will always print "1 2" on any compiler.
Is it necessary that function call should be implemented using stack only. what does C/C++ standards says about this.
This is known as "calling convention" and nothing that the standard specifies at all. How parameters (and return values) are passed, is entirely up to the implementation. They could be passed in CPU registers or on the stack, or in some other way. The caller could be the one responsible for pushing/popping parameters on the stack, or the function could be responsible.
The order of evaluation of function parameters is only somewhat associated with the calling convention, since the evaluation occurs before the function is called. But on the other hand, certain compilers can choose to put the right-most parameter in a CPU register and the rest of them on the stack, as one example.
Just only to speak for C language, the order of evaluation inside the function parameters depend on compiler. from The C Programming Language of Brian Kernighan and Dennis Ritchie;
Similarly, the order in which function arguments are evaluated is not
specified, so the statement
printf("%d %d\n", ++n, power(2, n)); /*WRONG */
can produce different results with different compilers,
depending on whether n is incremented before power is called. The
solution, of course, is to write
++n;
printf("%d %d\n", n, power(2, n));
As far as I know, the function printf has an exception here.
For an ordinary function foo, the order of evaluation of foo(bar(x++), baz(++x)) is undefined. Correct! However printf, being an ellipsis function has a somewhat more definite order of evaluation.
The printf in the standard library, in fact, has no information about the number of arguments that has been sent to. It just tries to figure out the number of variables from the string placeholders; namely, from the number of percent operators (%) in the string. The C compiler starts pushing arguments from the very right towards left; and the address of the string is passed as a last argument. Having no exact information about the number of arguments, printf evaluates the last address (the string) and starts replacing the %'s (from left to right) with values of the corresponding addresses in the stack. That is, for a printf like below;
{
int x = 0;
printf("%d %d %f\n", foo(x), bar(x++), baz(++x));
}
The order of evaluation is:
x is incremented by 1,
function baz is called with x = 1; return value is pushed to the stack,
function bar is called with x = 1; return value is pushed to the stack,
x is incremented by 1,
function foo is called with x = 2; return value is pushed to the stack,
the string address is pushed to the stack.
Now, printf has no information about the number of arguments that has been sent to. Moreover, if -Wall is not issued in compilation, the compiler will not even complain about the inconsistent number of arguments. That is; the string may contain 3 %'s but the number of arguments in the printf line can be 1, 2, 3, 4, 5 or even can contain just the string itself without any arguments at all.
Say, the string has 3 placeholders and you've send 5 arguments (printf("%d %f %s\n", k1, k2, k3, k4, k5)). If compilation warning is turned off, the compiler will not complain about excessive number of arguments (or insufficient number of placeholders). Knowing the stack address, printf will;
treat the first integer width in the stack and print it as an integer (without knowing whether it is an integer or not),
treat the next double width in the stack and print it as a double (without knowing whether it is a double or not),
treat the next pointer width in the stack as a string address and will try to print the string at that address, until it finds a string terminator (provided, the address pointed to belong to that process; otherwise raises segmentation error).
and ignore the remaining arguments.

Is each conversion associated with an input/out format specifier a Sequence Point in C?

Wikipedia entry on Sequence Points in C has this Sequence point:
After each conversion associated with an input/output format
specifier. For example, in the expression printf("foo %n %d", &a, 42),
there is a sequence point after the %n is evaluated and before
printing 42
But C standard also says:
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.
These two points seems contradictory in nature for codes like this
int i=1;
printf("%d, %d and %d\n", i++, i++, i--);
According to wikipedia entry after each format specifier there is a sequence point so it will be printed like:
1,2,3
But according to unspecified beaviour entry in C standard, it can print anything.
The Wikipedia page is poorly worded. The actual text is (C11 7.21.6):
The formatted input/output functions shall behave as if there is a sequence point after the actions associated with each specifier.
These actions all occur after the sequence point described by your quote "there is a sequence point before the actual call". The arguments and postfix-expression are evaluated; then the function is entered; then the actions specified by the format string occur in order.
The action associated with %i for example, is outputting the argument's value. You seem to be mixing up "output the argument" with "evaluate the argument"; the latter occurs before the function is entered.
Both the rules are correct. You are not reading them correctly.
First the second one -
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.
This means that the parameters to the function can be evaluated in any order. There is no sequence point between them.
Because of this a call like -
printf("%d, %d and %d\n", i++, i++, i--);
is not defined and invokes UB.
Now for the first one,
After each conversion associated with an input/output format specifier. For example, in the expression printf("foo %n %d", &a, 42), there is a sequence point after the %n is evaluated and before printing 42
This is not talking about the parameter evaluation but the actual printing. Whenever each format specifier like %d, %c, %n is evaluated (both for scanf and printf) it could have side effects. These effects are sequenced in the order the format specifier appears in the string.
For instance
scanf("%d %d", &a, &b); // a and b are integers
The store to a will be sequenced before the store to b.
Similarly in case of printf as given in the example,
printf("foo %n %d", &a, 42);
The update to a will be sequenced before the printing of 42.
There is no relation to how 42, &a, printf or "foo %n %d" is evaluated.
The format string is an argument to the function and as such, that argument (the string) is evaluated before the function is called. There's no special magic here, but all parameters to printf are evaluated in an unspecified order, just as with any function. (Code such as printf(ptr, ptr+n); is therefore fishy and invokes poorly-specified behavior.)
Then before the function is called there is a sequence point.
Wikipedia says "there is a sequence point after the %n is evaluated and before printing 42". This is something else entirely. There's a special guarantee that the %n as part of the format string, is evaluated before the parameter corresponding to that specifier is printed. Formally this is specified in C11:
7.21.6 Formatted input/output functions
The formatted input/output functions shall behave as if there is a sequence point after the actions associated with each specifier. 274)
This has nothing to do with the evaluation of the function arguments. So roughly, given this code:
printf("%d", i)
you'd have the following order of execution:
"%d" and i are evaluated in an unspecified order before the function is called.
Sequence point.
The function is called.
The string is parsed and the %d part is found and interpreted.
Sequence point.
i is printed.
Sequence point.
Function returns.
This special sequence point after format specifiers is apparently there because of the %n specifier specifically, which writes to memory according to a foot note:
274) The fprintf functions perform writes to memory for the %n specifier.

Array of Integers Changes Content When Passed to a Function [duplicate]

In C and C++, is there a fixed order for evaluation of parameter to the function? I mean, what do the standards say? Is it left-to-right or right-to-left?
I am getting confusing information from the books.
Is it necessary that function call should be implemented using stack only? What do the C and C++ standards say about this?
C and C++ are two completely different languages; don't assume the same rules always apply to both. In the case of parameter evaluation order, however:
C99:
6.5.2.2 Function calls
...
10 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.
[Edit]
C11 (draft):
6.5.2.2 Function calls
...
10 There is a sequence point after the evaluations of the function designator and the actual
arguments but before the actual call. Every evaluation in the calling function (including
other function calls) that is not otherwise specifically sequenced before or after the
execution of the body of the called function is indeterminately sequenced with respect to
the execution of the called function.94)
...
94) In other words, function executions do not ‘‘interleave’’ with each other.
C++:
5.2.2 Function call
...
8 The order of evaluation of arguments is unspecified. All side effects of argument expression evaluations take effect
before the function is entered. The order of evaluation of the postfix expression and the argument expression list is
unspecified.
Neither standard mandates the use of the hardware stack for passing function parameters; that's an implementation detail. The C++ standard uses the term "unwinding the stack" to describe calling destructors for automatically created objects on the path from a try block to a throw-expression, but that's it. Most popular architectures do pass parameters via a hardware stack, but it's not universal.
[Edit]
I am getting confusing information from the books.
This is not in the least surprising, since easily 90% of books written about C are simply crap.
While the language standard isn't a great resource for learning either C or C++, it's good to have handy for questions like this. The official™ standards documents cost real money, but there are drafts that are freely available online, and should be good enough for most purposes.
The latest C99 draft (with updates since original publication) is available here. The latest pre-publication C11 draft (which was officially ratified last year) is available here. And a publicly availble draft of the C++ language is available here, although it has an explicit disclaimer that some of the information is incomplete or incorrect.
Keeping it safe: the standard leaves it up to the compiler to determine the order in which arguments are evaluated. So you shouldn't rely on a specific order being kept.
In C/C++ is there a fixed order for evaluation of parameter to the function. I mean what does standards says is it left-to-right or right-to-left . I am getting confusing information from the books.
No, the order of evaluation of function parameters (and of two sub-expressions in any expression) is unspecified behaviour in C and C++. In plain English that means that the left-most parameter could be evaluated first, or it could be the right-most one, and you cannot know which order that applies for a particular compiler.
Example:
static int x = 0;
int* func (int val)
{
x = val;
return &x;
}
void print (int val1, int val2)
{
cout << val1 << " " << val2 << endl;
}
print(*func(1), *func(2));
This code is very bad. It relies of order of evaluation of print's parameters. It will print either "1 1" (right-to-left) or "2 2" (left-to-right) and we cannot know which. The only thing guaranteed by the standard is that both calls to func() are completed before the call to print().
The solution to this is to be aware that the order is unspecified, and write programs that don't rely on the order of evaluation. For example:
int val1 = *func(1);
int val2 = *func(2);
print(val1, val2); // Will always print "1 2" on any compiler.
Is it necessary that function call should be implemented using stack only. what does C/C++ standards says about this.
This is known as "calling convention" and nothing that the standard specifies at all. How parameters (and return values) are passed, is entirely up to the implementation. They could be passed in CPU registers or on the stack, or in some other way. The caller could be the one responsible for pushing/popping parameters on the stack, or the function could be responsible.
The order of evaluation of function parameters is only somewhat associated with the calling convention, since the evaluation occurs before the function is called. But on the other hand, certain compilers can choose to put the right-most parameter in a CPU register and the rest of them on the stack, as one example.
Just only to speak for C language, the order of evaluation inside the function parameters depend on compiler. from The C Programming Language of Brian Kernighan and Dennis Ritchie;
Similarly, the order in which function arguments are evaluated is not
specified, so the statement
printf("%d %d\n", ++n, power(2, n)); /*WRONG */
can produce different results with different compilers,
depending on whether n is incremented before power is called. The
solution, of course, is to write
++n;
printf("%d %d\n", n, power(2, n));
As far as I know, the function printf has an exception here.
For an ordinary function foo, the order of evaluation of foo(bar(x++), baz(++x)) is undefined. Correct! However printf, being an ellipsis function has a somewhat more definite order of evaluation.
The printf in the standard library, in fact, has no information about the number of arguments that has been sent to. It just tries to figure out the number of variables from the string placeholders; namely, from the number of percent operators (%) in the string. The C compiler starts pushing arguments from the very right towards left; and the address of the string is passed as a last argument. Having no exact information about the number of arguments, printf evaluates the last address (the string) and starts replacing the %'s (from left to right) with values of the corresponding addresses in the stack. That is, for a printf like below;
{
int x = 0;
printf("%d %d %f\n", foo(x), bar(x++), baz(++x));
}
The order of evaluation is:
x is incremented by 1,
function baz is called with x = 1; return value is pushed to the stack,
function bar is called with x = 1; return value is pushed to the stack,
x is incremented by 1,
function foo is called with x = 2; return value is pushed to the stack,
the string address is pushed to the stack.
Now, printf has no information about the number of arguments that has been sent to. Moreover, if -Wall is not issued in compilation, the compiler will not even complain about the inconsistent number of arguments. That is; the string may contain 3 %'s but the number of arguments in the printf line can be 1, 2, 3, 4, 5 or even can contain just the string itself without any arguments at all.
Say, the string has 3 placeholders and you've send 5 arguments (printf("%d %f %s\n", k1, k2, k3, k4, k5)). If compilation warning is turned off, the compiler will not complain about excessive number of arguments (or insufficient number of placeholders). Knowing the stack address, printf will;
treat the first integer width in the stack and print it as an integer (without knowing whether it is an integer or not),
treat the next double width in the stack and print it as a double (without knowing whether it is a double or not),
treat the next pointer width in the stack as a string address and will try to print the string at that address, until it finds a string terminator (provided, the address pointed to belong to that process; otherwise raises segmentation error).
and ignore the remaining arguments.

Unexpected working of printf() in C [duplicate]

This question already has answers here:
Why are these constructs using pre and post-increment undefined behavior?
(14 answers)
Closed 9 years ago.
#include<stdio.h>
int main()
{
int i=2;
printf("%d %d \n",++i,++i);
}
The above code gives an output 4 4. Can any one help how to explain the output?
++i is a prefix increment. Printf should first evaluate its arguments before printing them (although in which order, is not guaranteed and, strictly speaking, undefined - See Wiki entry on Undefined Behavior: http://en.wikipedia.org/wiki/Undefined_behavior ).
The prefix increment is called "increment and fetch", i.e. it first increments the value and then gives it to the caller.
In your case, i was first incremented twice, and only afterwards the output was formatted and sent to the console.
It has to do with sequence points and it can result in undefined behavior.
Straight from Wikipedia:
Before a function is entered in a function call. The order in which
the arguments are evaluated is not specified, but this sequence point
means that all of their side effects are complete before the function
is entered.
More info here: http://en.wikipedia.org/wiki/Sequence_point
Both the answers have made the same mistake. Its clear cut UB and not just unspecified behavior.
What you have experienced is Undefined behavior. Please read about sequence points. Comma is a separator in function calls not an operator.
A sequence point is a point in time at which the dust has settled and all side effects which have been seen so far are guaranteed to be complete. The sequence points listed in the C standard are:
at the end of the evaluation of a full expression (a full
expression is an expression statement, or any other expression which
is not a subexpression within any larger expression);
at the ||, &&, ?:, and comma operators; and
at a function call (after the evaluation of all the arguments, and just before the actual call).
The Standard states that
Between the previous and next sequence point an object shall have its
stored value modified at most once by the evaluation of an expression.
Furthermore, the prior value shall be accessed only to determine the
value to be stored.
What will be evaluated first this "%d %d \n", this ++i or this ++i (second one) - think about it. This would be unspecified behavior:
void f(int x)
{
printf("%d ",x);
}
int main()
{
int i=0;
f(i++) ;
}
From wiki:
Before a function is entered in a function call. The order in which
the arguments are evaluated is not specified, but this sequence point
means that all of their side effects are complete before the function
is entered. In the expression f(i++) + g(j++) + h(k++), f is called
with a parameter of the original value of i, but i is incremented
before entering the body of f. Similarly, j and k are updated before
entering g and h respectively. However, it is not specified in which
order f(), g(), h() are executed, nor in which order i, j, k are
incremented. Variables j and k in the body of f may or may not have
been already incremented. Note that a function call f(a,b,c) is not a
use of the comma operator and the order of evaluation for a, b, and c
is unspecified.

Is the output of printf ("%d %d", c++, c); also undefined?

I recently came across a post What is the correct answer for cout << c++ << c;? and was wondering whether the output of
int c = 0;
printf ("%d %d", c++, c);
is also undefined??
I have studied in lectures that post-fix and prefix operators increment value only after getting a semicolon. So according to me, the output 0 0 is correct !!!
I have studied in lectures that post-fix and prefix operators increment value only after getting a semicolon.
Send your lecturer to me so that I can take a baseball bat to him politely point out his mistake.
Exactly when the side effect of either pre- or postfix ++ and -- is applied is unspecified, apart from the requirement that it happen before the next sequence point. In an expression like
x = a++ * b
a may be updated immediately after a++ has been evaluated, or the update may be deferred until a++ * b has been evaluated and the result assigned to x, or anywhere in between.
This is why expressions like i++ * i++ and printf("%d %d", c++, c) and a[i++] = i and a host of others are all bad juju. You will get different results based on the compiler, optimization settings, surrounding code, etc. The language standard explicitly leaves the behavior undefined so that the compiler is under no obligation to "do the right thing", whatever the right thing may be. Remember, the definition for undefined behavior is
3.4.3
1 undefined behavior
behavior, upon use of a nonportable or erroneous program construct or of erroneous data,
for which this International Standard imposes no requirements
2 NOTE Possible undefined behavior ranges from ignoring the situation completely with unpredictable
results, to behaving during translation or program execution in a documented manner characteristic of the
environment (with or without the issuance of a diagnostic message), to terminating a translation or
execution (with the issuance of a diagnostic message).
3 EXAMPLE An example of undefined behavior is the behavior on integer overflow.
This is a deliberate design decision - the rationale for leaving the order of these operations unspecified is to give the implementation freedom to rearrange the evaluation order for optimization purposes. However, in exchange for this freedom, certain operations will not have well-defined results.
Note that a compiler is free to try to detect these cases and issue a diagnostic; printf("%d %d", c++, c); would be easy enough to catch, but this would be a bugger to detect in the general case. Imagine if that had been written printf("%d %d", (*p)++, c); if p points to c, then the behavior is undefined, otherwise it's okay. If p is assigned in a different translation unit, then there's no way to know at compile time whether this is a problem or not.
This concept is not difficult to understand, yet it is one of the most consistently misunderstood (and mis-taught) aspects of the C language. No doubt this is why the Java and C# language specifications force a specific evaluation order for everything (all operands are evaluated left-to-right, and all side effects are applied immediately).
I have studied in lectures that post-fix and prefix operators increment value only after getting a semicolon
This is not how the standard describes it. A sequence point is a point in code in which side effects which may have occurred in previous parts of the code have been evaluated. The comma between arguments to a function is not a sequence point, so the behavior there is undefined.
The evaluation order of function arguments is unspecified. There is no guarantee that the arguments to a function will be evaluated in the order (1, 2, N), so there is no guarantee that the increment will be evaluated before the second argument is passed.
So according to me, the output 0 0 is correct !!!
No, the behavior is undefined, so you cannot reasonably claim that the output will be 0 0.
The behavior of the program is undefined because it has violated the requirements of 6.5 Expressions:
Between the previous and next sequence point an object shall have its stored value modified at most once by the evaluation of an expression. Furthermore, the prior value shall be read only to determine the value to be stored.
c++ and c are both evaluated without an intervening sequence point, and the prior value of c is read both to determine the value to be stored by c++, and to determine the value of the expression c.
The behaviour will be definitely undefined due to the undefined evaluation order of parameters. You can prove this "undefined output" doing some random testing:
printf("%d %d\n", c++, c);
// result: 0 1
printf("%d %d %d\n", c++, c, c++);
// result: 1 2 0
printf("%d %d %d %d\n", c++, c++, c++, c);
// result: 2 1 0 3
printf("%d %d %d %d\n", c++, c, c++, c);
// result: 1 2 0 2
printf("%d %d %d %d\n", c++, c, c, c);
// result: 0 1 1 1
You are right: it is undefined. The reason is that, though it is guaranteed that the three arguments to printf() will be evaluated before printf() is called, the sequence in which the three arguments are evaluated is undefined.
It is technically incorrect that the incrementation occurs only after the semicolon, incidentally. What the standard guarantees is that the incrementation will occur no later than the semicolon. [Actually, in your case, I believe that the standard guarantees that it will occur before control is passed to the printf() function -- but now this answer is starting to spin off into realms of pedantic trivia, so let me let the matter rest there!]
Anyway, in short, you are right. The behavior is undefined.
Update: As #R.. rightly observes, the undefined behavior comes from the lack of a sequence point between arguments. The standard is quite careful regarding the participles unspecified and undefined, so the correction is accepted with thanks.
This program exhibits a combination of both unspecified behavior and undefined behavior. Starting with the unspecified behavior, the draft C99 standard in section6.5 paragraph 3 says:
The grouping of operators and operands is indicated by the syntax.74)
Except as specified later (for the function-call (), &&, ||, ?:, and
comma operators), the order of evaluation of subexpressions and the
order in which side effects take place are both unspecified.
It also says except as specified later and specifically cites function-call (), so we see that later on the draft standard in section 6.5.2.2 Function calls paragraph 10 says:
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.
So we do not know whether the read of C or the evaluation of C++ will happen first at this line of code:
printf ("%d %d", c++, c);
furthermore, in section 6.5.2.4 Postfix increment and decrement operators paragraph 2 says:
[...] After the result is obtained, the value of the operand is incremented. [...] The side effect of updating the stored value of the operand shall occur between the previous and the next sequence point.
So all we know is that when performing the post increment c will be updated after its value is read but before the next sequence point which is right before printf is called but nothing else. As for the undefined behavior, if we look at section 6.5 paragraph 2 from the draft standard, is says:
Between the previous and next sequence point an object shall have its stored value
modified at most once by the evaluation of an expression. Furthermore, the prior value
shall be read only to determine the value to be stored.
In the printf expression cs prior value is being read in order to evaluate both C++ and C and so we now are in undefined territory.

Resources