How does printf() really perform? - c

This documentation gives an example of how to write a varargs function, printf() .
As the documentation, printf() will find the first % in the string and use va_arg(argp, int) to get the first argument pointer; find the second % in the string and use va_arg(argp, int) again to get the second argument pointer......
So, I wrote a code snippet:
int Var = 0;
int Func (int X)
{
Var = Var + X;
return Var;
}
int main (void)
{
printf ("%d\n%d", Func (3), Func (5));
}
It will print:
8 <-- 5+3
5 <-- 5
I know calling multiple functions in printf() is undefined behavior, but why not print:
3 <-- 3
8 <-- 3+5
just as the sample code in that documentation?
ps: If my question is not clear, please help me edit it. Thanks

The order that function parameters are evaluated in C is platform dependent (not undefined, just unspecified).
See this blog that talks about it: Funny thing about C parameter evaluation order…
If you want to force the order, you would call Func() before the printf():
int a = Func(3);
int b = Func(5);
printf("%d\n%d", a, b);

While it's true that parameter evaluation order isn't defined, parameter placement is. The so called C calling convention states that parameters are pushed to the stack from right to left. This order is needed precisely to support variable parameter functions. Normally, as each parameter is evaluated, it is inmediately pushed into the stack (although some obscure optimizations in order to optimize memory writes might alter this), so we could expect that parameter evaluarion works by evaluating them from right to left.
That would mean that Func(5) is first evaluated, pushes 5 into the stack, then Func(3) is evaluated, pushing 8 to the stack. Parameter order, as it will be printed by printf are 8 and 5.

Related

How to understand the behaviour of printf statement in C?

I have come across two C aptitude questions.
main()
{
int x=4,y,z;
y=--x;
z=x--;
printf("\n%d %d %d",x,y,z);
}
Output: 2 3 3 (it is printed left to right)
main()
{
int k=35;
printf("\n%d %d %d",k==35,k=50,k>40);
}
Output: 0 50 0 (it is printed right to left)
Why is it so? I have seen so many similar answers on Stack Overflow similar to this. People answer this is undefined behaviour, but if this is asked in interviews, how should one answer them?
The order of the evaluation of the arguments to any function in C is not in any particular order. It looks like the platform / compiler you are being asked about is probably evaluating the functions arguments right-to-left, which would print out the result you obtained, but the C standard says you do not know the order, so what is shown here is undefined behavior and would almost certainly obtain different results on a different compiler or platform.
Note, in your function, all the variable values are assigned before calling printf() - while in your main(), the values are being assigned to the variable in printf()'s argument list.
Yes, you need to read the documentation of printf. Read it carefully and several times.
You should compile with all warnings and debug info, i.e. using gcc -Wall -Wextra -g with GCC. Improve your code to get no warnings. Then use the gdb debugger to understand the behavior of your program.
On the second example (where I added the missing but mandatory #include <stdio.h>) GCC 8.1 gives on Linux/x86-64/Debian:
% gcc -Wall -Wextra -g m.c -o myprog
m.c:3:1: warning: return type defaults to ‘int’ [-Wimplicit-int]
main()
^~~~
m.c: In function ‘main’:
m.c:6:29: warning: operation on ‘k’ may be undefined [-Wsequence-point]
printf("\n%d %d %d",k==35,k=50,k>40);
~^~~
m.c:6:29: warning: operation on ‘k’ may be undefined [-Wsequence-point]
Also, as explained by John's H answer the order of evaluation of arguments is undefined (and the compiler gives some clue). A good way to think of it is to believe it is random and could dynamically change (but few implementations behave like that), and to write your source code in such way that won't change the intended behavior of your program.
In
printf("\n%d %d %d",k==35,k=50,k>40);
// ^
you have an assignment operator. So k is changing. But you don't know exactly when (it could happen after or before the k==35 and k>40 comparisons). So you have undefined behavior, be very scared!
At last, stdout is often buffered (see setvbuf(3) & stdio(3) for more) and usually line buffered. So the buffer could be flushed by the \n which you'll better place at the end of the format control string. Otherwise, ensure flushing by calling fflush(3).
From the C standard C99, section 6.5
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 e valuation of sube xpressions and
the order in which side ef fects tak ep lace are both unspecified.
So C standard doesn't say anything like that the function argument are solved from right to left & printed from left to right.
case 1 :- The statement y=--x; results in y=3 and x=3. when the expression z=x--; is performed. After this x=2 and z=3. Finally when the printf statement executed
printf("\n%d %d %d",x,y,z);
it prints 2 3 3.
Case 2 :- Here x=35 and when printf statement executes
printf("\n%d %d %d",k==35, k=50, k>40);
| | | <---- R to L (in your machine, seems argument passed from R to L, but can't grantee same for other platform)
50==35 50 35>40
| | | ----> L to R
0 50 0
In between, the main() prototype you used is incorrect. It should be int main(void) { /*... */ } as specified in C standard here
The function called at program startup is named main. The
implementation declares no prototype for this function. It shall be
defined with a return type of int and with no parameters:
int main(void) { /* ... */ }
or with two parameters (referred to here as argc and argv, though any
names may be used, as they are local to the function in which they are
declared):
int main(int argc, char *argv[]) { /* ... */ }
Let's trace through the code.
Example 1:
main()
This is no longer correct (since 1999). main needs a return type: int main().
{
int x=4,y,z;
Here x = 4 whereas y and z are indeterminate.
y=--x;
--x decrements x (from 4 to 3) and returns the new value of x (3), which is then assigned to y. At the end we have x = 3, y = 3, and z still indeterminate.
z=x--;
x-- decrements x (from 3 to 2) and returns the old value of x (3), which is then assigned to z. At the end we have x = 2, y = 3, z = 3.
printf("\n%d %d %d",x,y,z);
Here we're calling printf, but the function is not declared. The code is missing #include <stdio.h>; without it, the behavior is undefined (because it's calling an undeclared varargs function). But let's assume <stdio.h> was included. Then:
This outputs x, y, z as 2 3 3. Note that the format string should be "%d %d %d\n"; in the C model, lines are terminated by '\n', so you should always have a '\n' at the end.
}
Example 2:
main()
Same issue, should be int main() and #include <stdio.h> is missing.
{
int k=35;
Now k = 35.
printf("\n%d %d %d",k==35,k=50,k>40);
This is just broken. Function arguments can be evaluated in any order. In particular, the assignment to k (k = 50) and the comparisons (k == 35, k > 40) are not sequenced relative to each other, which means this piece of code has undefined behavior. You're not allowed to modify a variable while at the same time reading from it.
}
People answer this is undefined behaviour, but if this is asked in interviews, how should one answer them?
Tell them "this is undefined behavior". That's the correct answer. The example above is not required to produce any output. It could print 1 2 3, but it also could print hello!, or go into an infinite loop, or crash, or delete all of your files.
As far as the C standard is concerned, the code is simply meaningless.
(What happens on any particular platform is highly dependent on your compiler, the exact version of the compiler, any optimization options used, etc.)
I have seen so many similar answers on Stack Overflow similar to this.
People answer this is undefined behaviour,
And that's quite often the only correct answer.
but if this is asked in interviews, how should one answer them?
If your interviewer truly knows C, but chooses to ask this sort of question, it can be thought of as a trick question. They might seem to be expecting an answer like "1 50 1", but really they do expect the correct answer, which is, "It's undefined."
So if I were asked this question, I would give the interviewer a look suggesting "I can't believe you're asking me this", but then say, confidently, "It's undefined."
If the interviewer doesn't realize it's undefined, you have somewhat of a problem, but that's a human psychology and interview strategy question, not a C programming question, so I think I'll avoid delving into it further.

confusion about static int and calling them in printf

Please test this code and give me your answers :
#include <stdio.h>
int func() {
static int n = 0;
n++;
return n;
}
int main() {
/*int first = func();
int second = func();*/
printf(" first call : %d \n second call : %d ",func(),func());
return 0;
}
Logically it should print 1 and 2 but it is printing 2 and 1 .
If you Un-Comment the comments and print the variables "first" and "second" , the problem is solved!
What is happening?
thank you already!
The order in which a function call's arguments are evaluated is unspecified, i.e., the compiler is free to make the two func() calls in any order before passing the return values to printf. If you first assign the results to variables, obviously you get to decide in which order they are used.
The order in which the parameters to a function are passed is not defined in the standard, and is determined by the calling convention used by the compiler. I think in your case, cdecl calling convention (which many C compilers use for x86 architecture) is used in which arguments in a function get evaluated from right to left.
because while calling the function it takes right associative..
i.e, the last one in printf gets called first then the before one.. thats why it is printing 2 then 1.
try using two print statements like:
printf("First call: %d\n",func());
printf("second call: %d\n",func());

C equivalent operator creating confusion

Program 1:
#include<stdio.h>
void main()
{
int i=55;
printf("%d %d %d %d\n",i==55,i=40,i==40,i>=10);
}
Program 2:
#include<stdio.h>
void main(){
int i = 55;
if(i == 55) {
printf("hi");
}
}
First program give output 0 40 0 1 here in the printf i == 55 and output is 0 and in the second program too i ==55 and output is hi. why
In the first example, the operators are evaluated in reverse order because they are pushed like this on the stack. The evaluation order is implementation specific and not defined by the C standard. So the squence is like this:
i=55 initial assignment
i>=10 == true 1
i==40 == false (It's 55) 0
i=40 assignment 40
i==55 == false (It's 40) 0
The second example should be obvious.
There's no guarantee about the order in which arguments to a function are evaluated. There's also no sequence point between evaluating the different arguments to the function.
That means your first call gives undefined behavior, because it both uses the existing value of i and writes a new value to i without a sequence point between the two.
In a typical case, however, each argument to a function will be evaluated as a separate expression, with no interleaving between them. In other words, the compiler will impose some order to the evaluation, even though the standard doesn't require it to do so.
In the specific case of a variadic function, the arguments are typically pushed onto the stack from right to left, so the first argument (the format string) will be at the top of the stack. This makes it easy for printf to find the format string, and then (based on that) retrieve the rest of the arguments from further down the stack.
If (as is fairly typical) the arguments are evaluated immediately prior to being pushed on the stack, this will lead to the arguments being evaluated from right to left as well.
Functions with a fixed number of arguments aren't evaluated from right to left nearly as often, so if (for example) you wrote a small wrapper taking a fixed number of arguments, that then passed those through to printf, there's a greater chance that i would have the value 55 when the first argument to printf is evaluated, so that would produce a 1 instead of a 0.
Note, however, that neither result is guaranteed, nor is any meaningful result guaranteed--since you have undefined behavior, anything is allowed to happen.
The arguments of printf are evaluated from right to left here (this is unspecified behavior, but the behaviour you noticed shows that at least the first argument is evaluated after the second). In your argument list there ist i=40, which sets the value to 40. Therefore the first printed argument is false (0).
The function printf evaluates the expressions in implementation specific manner, in this case from right to left. Hence the output:
i==55(0),i=40(Assignment),i==40(0),i>=10(1)
The reason is that the order in which the arguments to the printf function (actually any function) are evaluated, before being passed to the function, is not defined by the C standard.
The problem is not with your understanding of the == operator.
Edit: Although many authors are pointing out that printf typically evaluates its arguments from right-to-left (which I wasn't aware of), I would say it's probably a bad idea to write code that depends on this, as the language does not guarantee it, and it makes the code much less readable. Nevertheless is is a good factoid to know in case you come across it in the wild.
In the first program: The order of evaluation of the printf() arguments is implimentation defined. So this program doesn't give the same result on different implimentation of printf() So there is no guarantee about what the program will result.
It could output 0 40 0 1 as it could output 1 40 1 1 if the order of evaluation is reversed.

Call an expression multiple times in an expression

I'm a student and new to C. One of the questions for my homework reads as follows:
max is a function that accepts two int parameters and returns the
value of the larger one. Four int variables, population1 ,
population2 , population3 , and population4 have already been
declared and initialized. Write an expression (not a statement!)
whose value is the largest of population1 , population2 ,
population3 , and population4 by calling max . (HINT: you will need
to call max three times and you will need to pass the return values
of two of those calls as arguments to max . REMEMBER: write an
expression, not a statement.)
I understand the logic of it:
Call the function max with the first two variables, the function will return the larger of the two and then take that value (somehow pass it without assigning to a fifth declared variable) and compare it to the third variable's value. Take the larger of the second pairing (again passing it without the benefit of a new variable - remember it's an expression, not a statement) and compare it to the forth value. However I haven't been able to write the correct syntax.
Also, understand that this is a 100 level class. So anything higher level will not be accepted for this particular question. No libraries to be #include(d).
Well you seem to understand how to do it, and yes the question seems to ask you to not assign returned values to new varibles. You can basically chuck in a max() as a parameter to another max(), and the return of the inner max() will be the int for the outer max() parameter.
Since c is strict, it won't compile unless the return type for the function is the same as the parameter (in this case, both are int, so it's fine)
max(2, max(3, 4)); // inner returns 4, which puts 4 into the outer max, and compares 2 to 4
Function calls can be nested. Here's a hint:
max(population1, max(...))
Can you come up with the correct code for the ...?
A function which returns something different that nothing (void) can be used inside an expression freely. An expression is defined recursively since it is made by sub-expressions until you reach terminal symbols (as constants or function calls).
So there is nothing strange in understanding the syntax, a call to max is synctatically equivalent to a numeric constant.
int x = 5;
int y = max(5,10);
int z = 5 + 10;
int k = max(5,10) + 3;
int j = max(3 + 2, 8);
These are all legal. Of course the assignment is just for clarity, as as assignment is a statement, not just an expression anymore.

arguments are reversed for a C function

I have a function that multiply two matrices A and B then prints the result.
I got two different outputs when running the program in two similar ways.
first:
FILE *f;
f = fopen("in.txt","r");
struct Mat* A = read_mat(f);
struct Mat* B = read_mat(f);
print_mat(mat_mul_1(A, B));
the output was the exact multiplication of
A * B
second:
FILE *f;
f = fopen("in.txt","r");
print_mat(mat_mul_1(read_mat(f), read_mat(f)));
the output was the exact multiplication of
B * A
I want to know why the arguments has been reversed ?!
(as the 'mat_mul_1' function is a black box)
Did you expect that the first read_mat(f) would be evaluated first?
C offers no such guarantees. The compiler is free to emit code that evaluates the arguments in any order it chooses.
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.
The reason why is as others have already pointed out, the order of evaluation of function parameters is unspecified behavior, and therefore should not be relied upon. But there is another, possibly severe issue here:
The function read_mat could be accessing static resources, such as static/global variables, and then return their values. Like this:
static int x;
int inc (void)
{
x++;
return x;
}
printf("%d %d", inc(), inc());
The actual result of the function will vary depending on the order of evaluation.
(This snippet is taken from an interview test I use when hiring C programmers. I ask what the output of this code is, and the correct answer is "2 1" or "1 2". The question tests whether the C programmer knows of the concepts static initialization and order of evaluation.)
It's because of the order parameters to the function are evaluated:
print_mat(mat_mul_1(A, B));
will call mat_mul_1(A, B), where A is the first matrix in the file and B is the second.
In your second case:
print_mat(mat_mul_1(read_mat(f), read_mat(f)));
I'm guessing(since it's not specified by the standard) that, on your system, is calling the second read_mat() first, and will thus call mat_mul_1(B, A);
The reason being is that the right-most read_mat(f) is called before the left-most one, and you're therefore reading the first structure into what you would presume to be B. Therefore A and B are reversed.
I kind of make sense of it in that arguments are pushed on the stack in reverse when they're passed to a function, therefore they're evaluated from right to left.
I'm not sure there's any standard defining what must be evaluated first.
Your code has undefined behaviour because the FILE pointed to by f is modified by both the first and the second read_mat(f) and no sequence point exists between these two modifications.

Resources