Call by Need and Standard C Output? - c

The following code is here with keep the C Language Syntax:
#include <stdio.h>
int func(int a, int b){
if (b==0)
return 0;
else return func(a,b);
}
int main(){
printf("%d \n", func(func(1,1),func(0,0)));
return 0;
}
What is the output of this code at 1) run with standard C, 2) with any
language that has call by need property, Then:
in (1) the programs loop into infinite call and in (2) we have ouptut zero !! this is an example solved by TA in programming language course, any idea to
describe it for me? thanks

1) In C (which uses strict evaluation semantics) we get infinite recursion because in strict evaluation arguments are evaluated before a function is called. So in f(f(1,1), f(0,0)) f(1,1) and f(0,0) are evaluated before the outer f (which one of the two arguments is evaluated first is unspecified in C, but that does not matter). And since f(1,1) causes infinite recursion, we get infinite recursion.
2) In a language using non-strict evaluation (be it call-by-name or call-by-need) arguments are substituted into the function body unevaluated and are only evaluated when and if they're needed. So the outer call to f is evaluated first as such:
if (f(0, 0) == 0)
return 0;
else return f(f(1,1), f(0,0));
So when evaluating the if, we need to evaluate f(0,0), which simply evaluates to 0. So we go into the then-branch of the if and never execute the else-branch. Since all calls to f are only used in the else-branch, they're never needed and thus never evaluated. So there's no recursion, infinite or otherwise, and we just get 0.

With C, in general, it is not defined the order of arguments a and b evaluation with a function like int func(int a, int b)
Obviously evaluating func(1,1) is problematic and the code suffers from that regardless if func(1,1) is evaluated before/after/simultaneous with func(0,0)
Analysis of func(a,b) based on need may conclude that if b==0, no need to call func() and then replace with 0.
printf("%d \n", func(func(1,1),func(0,0)));
// functionally then becomes
printf("%d \n", func(func(1,1),0));
Applied again and
// functionally then becomes
printf("%d \n", 0);
Of course this conclusion is not certain as the analysis of b != 0 and else return func(a,b); leads to infinite recursion. Such code may have a useful desired side-effect (e.g. stack-overflow and system reset.) So the analysis may need to be conservative and not assume func(1,1) will ever return and not optimize out the call even if it optimized out the func(0,0) call.

To address the first part,
The C Draft, 6.5.2.2->10(Function calls) says
The order of evaluation of ... the actual arguments... is unspecified.
and for such reason, something such as
printf("%d%d",i++,++i);
has undefined behaviour, because
both ++i and i++ has side-effects, ie incrementing the value of i by one.
The comma inside printf is just a separator and NOT a [ sequence point ].
Even though function call itself is a sequence point, for the above reason, the order in which two modifications of i take place is not defined.
In your case
func(func(1,1),func(0,0))
though, the arguments for outer func ie func(1,1) or func(0,0) have no bearing on each other contrary to the case shown above. Any order of evaluation of these arguments eventually leads to infinite recursion and so the program crashes due to depleted memory.

Related

Why are statements with no effect considered legal in C?

Pardon if this question is naive. Consider the following program:
#include <stdio.h>
int main() {
int i = 1;
i = i + 2;
5;
i;
printf("i: %d\n", i);
}
In the above example, the statements 5; and i; seem totally superfluous, yet the code compiles without warnings or errors by default (however, gcc does throw a warning: statement with no effect [-Wunused-value] warning when ran with -Wall). They have no effect on the rest of the program, so why are they considered valid statements in the first place? Does the compiler simply ignore them? Are there any benefits to allowing such statements?
One benefit to allowing such statements is from code that's created by macros or other programs, rather than being written by humans.
As an example, imagine a function int do_stuff(void) that is supposed to return 0 on success or -1 on failure. It could be that support for "stuff" is optional, and so you could have a header file that does
#if STUFF_SUPPORTED
#define do_stuff() really_do_stuff()
#else
#define do_stuff() (-1)
#endif
Now imagine some code that wants to do stuff if possible, but may or may not really care whether it succeeds or fails:
void func1(void) {
if (do_stuff() == -1) {
printf("stuff did not work\n");
}
}
void func2(void) {
do_stuff(); // don't care if it works or not
more_stuff();
}
When STUFF_SUPPORTED is 0, the preprocessor will expand the call in func2 to a statement that just reads
(-1);
and so the compiler pass will see just the sort of "superfluous" statement that seems to bother you. Yet what else can one do? If you #define do_stuff() // nothing, then the code in func1 will break. (And you'll still have an empty statement in func2 that just reads ;, which is perhaps even more superfluous.) On the other hand, if you have to actually define a do_stuff() function that returns -1, you may incur the cost of a function call for no good reason.
Simple Statements in C are terminated by semicolon.
Simple Statements in C are expressions. An expression is a combination of variables, constants and operators. Every expression results in some value of a certain type that can be assigned to a variable.
Having said that some "smart compilers" might discard 5; and i; statements.
Statements with no effect are permitted because it would be more difficult to ban them than to permit them. This was more relevant when C was first designed and compilers were smaller and simpler.
An expression statement consists of an expression followed by a semicolon. Its behavior is to evaluate the expression and discard the result (if any). Normally the purpose is that the evaluation of the expression has side effects, but it's not always easy or even possible to determine whether a given expression has side effects.
For example, a function call is an expression, so a function call followed by a semicolon is a statement. Does this statement have any side effects?
some_function();
It's impossible to tell without seeing the implementation of some_function.
How about this?
obj;
Probably not -- but if obj is defined as volatile, then it does.
Permitting any expression to be made into an expression-statement by adding a semicolon makes the language definition simpler. Requiring the expression to have side effects would add complexity to the language definition and to the compiler. C is built on a consistent set of rules (function calls are expressions, assignments are expressions, an expression followed by a semicolon is a statement) and lets programmers do what they want without preventing them from doing things that may or may not make sense.
The statements you listed with no effect are examples of an expression statement, whose syntax is given in section 6.8.3p1 of the C standard as follows:
expression-statement:
expressionopt ;
All of section 6.5 is dedicated to the definition of an expression, but loosely speaking an expression consists of constants and identifiers linked with operators. Notably, an expression may or may not contain an assignment operator and it may or may not contain a function call.
So any expression followed by a semicolon qualifies as an expression statement. In fact, each of these lines from your code is an example of an expression statement:
i = i + 2;
5;
i;
printf("i: %d\n", i);
Some operators contain side effects such as the set of assignment operators and the pre/post increment/decrement operators, and the function call operator () may have a side effect depending on what the function in question does. There is no requirement however that one of the operators must have a side effect.
Here's another example:
atoi("1");
This is calling a function and discarding the result, just like the call printf in your example but the unlike printf the function call itself does not have a side effect.
Sometimes such a statements are very handy:
int foo(int x, int y, int z)
{
(void)y; //prevents warning
(void)z;
return x*x;
}
Or when reference manual tells us to just read the registers to archive something - for example to clear or set some flag (very common situation in the uC world)
#define SREG ((volatile uint32_t *)0x4000000)
#define DREG ((volatile uint32_t *)0x4004000)
void readSREG(void)
{
*SREG; //we read it here
*DREG; // and here
}
https://godbolt.org/z/6wjh_5

Can the post-increment operator be used in the parameters of a function call? in C?

My question pertains to function calls in general, but I thought of it
while I was writing a priority queue using a heap. Just to give some context (not that it matters much) my heap stores items top to bottom left to right and I represent the heap as an array of structures. Upon inserting a new item, I just put it in the last place in the heap and then call the function "fix_up" at the bottom which will move the item to the proper place in the heap. I am wondering if instead of doing...
fix_up(pQueue->heap, pQueue->size);
pQueue->size++;
...I could just do...
fix_up(pQueue->heap, pQueue->size++);
I am unsure as to if this is ok for a few reasons.
1) Since pQueue->size is in the function call, I'm not even sure if it's actually pQueue->size or rather a copy of the integer stored in pQueue->size. If it was a copy then obviously I wouldn't be adding 1 to the actual pQueue->size so there'd be no point in doing this.
2) Since it's a function call, it is going to then go into the function fix_up and execute all the code there. I am wondering if this would have an unintended consequence of maybe when it went to fix_up it would get incremented by 1 and my index would be 1 higher than I intended while executing fix_up? Or would it do what it's supposed to do and wait until after fix_up had finished executing?
3) Even if it is ok, is it considered a good coding practice for C?
Status priority_queue_insert(PRIORITY_QUEUE hQueue, int priority_level, int data_item)
{
Priority_queue *pQueue = (Priority_queue*)hQueue;
Item *temp_heap;
int i;
/*Resize if necessary*/
if (pQueue->size >= pQueue->capacity) {
temp_heap = (Item*)malloc(sizeof(Item) * pQueue->capacity * 2);
if (temp_heap == NULL)
return FAILURE;
for (i = 0; i < pQueue->size; i++)
temp_heap[i] = pQueue->heap[i];
pQueue->capacity *= 2;
}
/*Either resizing was not necessary or it successfully resized*/
pQueue->heap[pQueue->size].key = priority_level;
pQueue->heap[pQueue->size].data = data_item;
/*Now it is placed as the last item in the heap. Fixup as necessary*/
fix_up(pQueue->heap, pQueue->size);
pQueue->size++;
//continue writing function code here
}
Yes you can.
However, you cannot do this:
foo(myStruct->size++, myStruct->size)
The reason is that the C standard does not say in which order the arguments should be evaluated. This would lead to undefined behavior.
1) Since pQueue->size is in the function call, I'm not even sure if it's actually pQueue->size or rather a copy of the integer stored in pQueue->size. If it was a copy then obviously I wouldn't be adding 1 to the actual pQueue->size so there'd be no point in doing this.
Whatever argument you're sending to a function, it will be evaluated before the function starts to execute. So
T var = expr;
foo(var);
is always equivalent to
foo(expr);
2) Since it's a function call, it is going to then go into the function fix_up and execute all the code there. I am wondering if this would have an unintended consequence of maybe when it went to fix_up it would get incremented by 1 and my index would be 1 higher than I intended while executing fix_up? Or would it do what it's supposed to do and wait until after fix_up had finished executing?
See above
3) Even if it is ok, is it considered a good coding practice for C?
Somewhat subjective, and a bit OT for this site, but I'll answer it anyway from my personal view. In general, I would try to avoid it.
Though, the other posts already answer this question, but none of them talk about role of Sequence Point, in this particular case, which can greatly help in clarifying OP's doubt.
From this [emphasis mine]:
There is a sequence point after the evaluation of all function arguments and of the function designator, and before the actual function call.
From this [emphasis mine]:
Increment operators initiate the side-effect of adding the value 1 of appropriate type to the operand. Decrement operators initiate the side-effect of subtracting the value 1 of appropriate type from the operand. As with any other side-effects, these operations complete at or before the next sequence point.
Also, the post increment operator increase the value of operand by 1 but the value of the expression is the operand's original value prior to the increment operation.
So, in this statement:
fix_up(pQueue->heap, pQueue->size++);
the value of pQueue->size will be increased by 1 before the fix_up() function call but the argument value will be the original value prior to the increment operation.
Yes you can use it directly in the expression you pass as argument.
A statement like
fix_up(pQueue->heap, pQueue->size++);
is somewhat equivalent to
{
int old_value = pQueue->size;
pQueue->size = pQueue->size + 1;
fix_up(pQueue->heap, old_value);
}
A note about the "equivalent" example above. Since the order of evaluation of arguments to function calls is not specified, the actual increment of pQueue->size could happen after the call to fix_up. And it also means that using pQueue->size more than once in the same call would lead to undefined behavior.
Yeah you can use it in function calls, but please note that your two examples are not equivalent. The pQueue->heap argument may be evaluated before or after pQueue->size++ and you can't know or rely on the order. Consider this example :
int func (void)
{
static int x = 0;
x++;
return x;
}
printf("%d %d", func(), func());
This will print 1 2 or 2 1 and we can't know which we'll get. The compiler need not evalute the function parameters consistently throughout the program. So if we add a second printf("%d %d", func(), func()); we could get something like 1 2 4 3 as output.
The importance here is to not write code which relies on order of evaluation. Which is the same reason as mixing ++ with other operations or side-effects in the same expression is bad practice. It can even lead to undefined behavior in some cases.
To answer your questions:
1) Since pQueue->size is in the function call, I'm not even sure if it's actually pQueue->size or rather a copy of the integer stored in pQueue->size. If it was a copy then obviously I wouldn't be adding 1 to the actual pQueue->size so there'd be no point in doing this.
The ++ is applied to the variable in the caller, so this isn't an issue. The local copy of the variable happens during function call, independently of the ++. However, the result of a ++ operation is not a so-called "lvalue" (addressable data), so this code is not valid:
void func (int* a);
...
func(&x++);
++ takes precedence and is evaluted first. The result is not an lvalue and cannot have its address taken.
2) Since it's a function call, it is going to then go into the function fix_up and execute all the code there. I am wondering if this would have an unintended consequence of maybe when it went to fix_up it would get incremented by 1 and my index would be 1 higher than I intended while executing fix_up? Or would it do what it's supposed to do and wait until after fix_up had finished executing?
This isn't an issue unless the function modifies the original variable through a global pointer or such. In that case you would have problems. For example
int* ptr;
void func (int a)
{
*ptr = 1;
}
int x=5;
ptr = &x;
func(x++);
This is very questionable code and x will be 1 after the line func(x++); and not 6 as one might have expected. This is because the function call expression is evaluated and finished before the function call.
3) Even if it is ok, is it considered a good coding practice for C?
It will work ok in your case but it is bad practice. Specifically, mixing the ++ or -- operators together with other operators in the same expression is bad (although common) practice, since it has a high potential for bugs and tends to make code less readable.
Your original code with pQueue->size++; on a line of it's own is superior in every way - stick with that. Contrary to popular belief, when writing C, you get no bonus points for "most operators on a single line". You may however get bugs and maintenance problems.

Interpretation of instructions without effect

How can we interpret the following program and its success?(Its obvious that there must not be any error message). I mean how does compiler interpret lines 2 and 3 inside main?
#include <stdio.h>
int main()
{
int a,b;
a; //(2)
b; //(3)
return 0;
}
Your
a;
is just an expression statement. As always in C, the full expression in expression statement is evaluated and its result is immediately discarded.
For example, this
a = 2 + 3;
is an expression statement containing full expression a = 2 + 3. That expression evaluates to 5 and also has a side-effect of writing 5 into a. The result is evaluated and discarded.
Expression statement
a;
is treated in the same way, except that is has no side-effects. Since you forgot to initialize your variables, evaluation of the above expression can formally lead to undefined behavior.
Obviously, practical compilers will simply skip such expression statements entirely, since they have no observable behavior.
That's why you should use some compilation warning flags!
-Wall would trigger a "statement with no effect" warning.
If you want to see what the compilation produces, compile using -S.
Try it with your code, with/without -O (optimization) flag...
This is just like you try something like this:
#include <stdio.h>
int main(void){
1;
2;
return 0;
}
As we can see we have here two expressions followed by semicolon (1; and 2;). It is a well formed statement according to the rules of the language.
There is nothing wrong with it, it is just useless.
But if you try to use though statements (a or b) the behavior will be undefined.
Of course that, the compiler will interpret it as a statement with no effect
L.E:
If you run this:
#include <stdio.h>
int main(void){
int a;
int b;
printf("A = %d\n",a);
printf("B = %d\n",b);
if (a < b){
printf("TRUE");
}else{
printf("FALSE");
}
return 0;
}
You wil get:
A = 0
B = 0
FALSE
Because a and b are set to 0;
Sentences in C wich are not control structures (if, switch, for, while, do while) or control statements (break, continue, goto, return) are expressions.
Every expression has a resulting value.
An expression is evaluated for its side effects (change the value of an object, write a file, read volatile objects, and functions doing some of these things).
The final result of such an expression is always discarded.
For example, the function printf() returns an int value, that in general is not used. However this value is produced, and then discarded.
However the function printf() produces side effects, so it has to be processed.
If a sentence has no side effects, then the compiler is free to discard it at all.
I think that for a compiler will not be so hard to check if a sentence has not any side effects. So, what you can expect in this case is that the compiler will choose to do nothing.
Moreover, this will not affect the observable behaviour of the program, so there is no difference in what is obtained in the resulting execution of the program. However, of course, the program will run faster if any computation is ignored at all by the compiler.
Also, note that in some cases the floating point environment can set flags, which are considered side-effects.
The Standard C (C11) says, as part of paragraph 5.1.2.3p.4:
An actual implementation need not evaluate part of an expression if it
can deduce that its value is not used and that no needed side effects
are produced [...]
CONCLUSION: One has to read the documentation of the particular compiler that oneself is using.

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.

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 unspeciļ¬ed, 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