Hidden rocks of func3(func1(), func2())? - c

Is there any problem with using another function call as a function parameter in C?
int foo1(int a){/*does something */ return a;}
int foo2(int b){/*does something */ return b;}
int foo3(int a, int b){return a+b;}
int result = foo3(foo1(1),foo2(2)); /*result is 3 */

To expand on tstanisl's comment
int foo1(int a) { puts("ONE"); return a++; }
int foo2(int b) { puts("TWO"); return b++; }
int foo3(int a, int b) { return a+b; }
int result = foo3(foo1(1),foo2(2));
There is no specific order for the prints. Any of
ONE TWO
TWO ONE
is possible. Can even change next time you recompile (or run) your executable!

There's no problem with the code in your question.
That code looks very much like it's intended to demonstrate a potential problem with calls like foo3(foo1(1),foo2(2)), but it fails to do so.
For example:
int foo1(int a){return a++;}
The expression a++ has a side effect, but one that's irrelevant. The parameter a is a local variable, and it ceases to exist when the function returns. It might as well be just return a; (except for possible undefined behavior if the increment overflows).
This:
int n = 42;
int func(int param) { return param++; }
returns the value 42 and does not affect the value of n. The ++ applies to a copy of n, not to n itself. Function arguments in C are passed by value.
The potential problem with that kind of call is that the order of the evaluation of the arguments is unspecified. The calls foo1(1) and foo2(2) have no side effects that are visible to the caller, but a call like foo3(a++, a++) would, and could yield different results depending on the unspecified order in which the arguments are evaluated. (I'm not 100% certain whether that case has undefined behavior; it depends on whether there's a sequence point between the evaluations of the arguments. But that uncertainty alone is more than enough reason to avoid writing code like that.)

Related

Can the place of function declaration in C affect the branch prediction?

Here's a code:
#include <stdio.h>
/* declaration */
int square (int num);
int main() {
int x, result;
x = 5;
result = square(x);
printf("%d squared is %d\n", x, result);
return 0;
}
/* definition */
int square (int num) {
int y;
y = num * num;
return(y);
}
And when I change it like this:
#include <stdio.h>
/* declaration */
int main() {
int x, result;
x = 5;
result = square(x);
printf("%d squared is %d\n", x, result);
return 0;
}
/* definition */
int square (int num);
int square (int num) {
int y;
y = num * num;
return(y);
}
I get the warning:
Implicit declaration of the function 'square'
Does this warning has any relation with the branch prediction things? Does the former code improves branch prediction and hence the performance of the code (as the function call branches/diverts the execution from the normal execution of the code!?)
No, it has nothing to do with branch prediction.
The language requires that a declaration of a function appear before the function is called. The compiler needs to see the declaration in order to generate code for the function call that is even correct, let alone performant: to know what types are expected as parameters, what type is returned, how the parameters should be laid out in the stack and registers, and so on. And by the one-pass design of the C language, this means the declaration has to appear before the function call. It's true that the necessary information is further down in the source file, but that's too late - the compiler isn't designed to "peek ahead" for it.
In modern C, the absence of the declaration makes the program invalid, and the compiler must issue a diagnostic. Previous versions of the C language allowed such a program to compile, using an "implicit declaration" which was essentially a standard set of rules to guess what types were expected and returned, and how they should be passed. Some compilers, such as gcc, proceed under these earlier rules when they find a missing declaration, and only give a warning instead of an error (which complies with the requirement for a diagnostic). But as the programmer, you really should consider it an error, since there's a good chance that the "guessed" implicit declaration will be wrong for your function, in which case the compiled program may fail in unpredictable ways at runtime.

Why is this function not pure?

In the Wikipedia article https://en.wikipedia.org/wiki/Pure_function#Impure_functions it says that the following function is not pure.
int f(int* x)
{
return *x;
}
Why is that? The function would return the same value for the same argument right? Would it be considered pure if it was a non-mutable reference, as in the following?
int f2(const int* x)
{
return *x;
}
f isn't pure because its return value isn't necessary the same for the same arguments. You could call f twice with the same inputs and get different outputs. The following program demonstrates this:
#include <stdio.h>
int main() {
int i = 3;
int * const x = &i;
printf("%d\n", f(x));
i = 4;
printf("%d\n", f(x));
return 0;
}
Because x doesn't change between the two calls, the second call to f(x) could be optimized away (in favour of reusing the result from the first call) if f was pure. Obviously, that could produce the wrong result, so f isn't pure.
f2 isn't pure for the same reason.
Rule 1 says:
Its return value is the same for the same arguments (no variation with local static variables, non-local variables, mutable reference arguments or input streams from I/O devices).
The point is that the argument is not the value pointed by x but rather the address of the pointer. You're passing an address to the function.
Since you can change the pointed data and pass the same address then you have different return values.
Of course this wouldn't be true if f or f2 returned int* instead that int. In that case the same argument would lead to the same return value.

how to pass a condition as parameter to function in C?

I have created an array of function pointers to swap two variables.
pointer pointing to these functions namely: swap1, swap2. swap3 and swap4.
swap2 is swaping using pointer passed as arguments.
but while declaring the function pointer, only int and int are passed as arguments. after compiling this causes many warnings.
so do we have a better way of passing the argument, where we put condition in function call itself.
code is given below.
#include <stdio.h>
int swap1(int ,int );
int swap2(int* ,int* );
int swap3(int ,int );
int swap4(int, int);
int swap1(int a,int b)
{
int temp=a;
a=b;
b=temp;
printf("swapped with 3rd variable :%d, %d\n", a,b);
}
int swap2(int *a,int *b)
{
int temp = *a;
*a = *b;
*b = temp;
printf("swapped with pointer :%d, %d\n", *a,*b);
}
int swap3(int a,int b)
{
a+=b;
b=a-b;
a-=b;
printf("swapped with 2 variable :%d, %d\n", a,b);
}
int swap4(int a,int b)
{
a=a^b;
b=a^b;
a=a^b;
printf("swapped with bitwise operation :%d, %d\n", a,b);
}
int main()
{
int ch;
int a=3;
int b=4;
printf("enter the option from 0 to 3\n");
scanf("%d",&ch);
int (*swap[4])(int, int) ={swap1,swap2,swap3,swap4};// function pointer
/*can we pass something like int(*swap[4]( condition statement for 'pointer to variable' or 'variable')*/
if (ch==1)// at '1' location, swap2 is called.
{
(*swap[ch])(&a,&b);//passing the addresses
}
else
{
(*swap[ch])(a,b);
}
return 0;
}
some warnings are as follows.
at line 36 in file '9e748221\script.c'
WARNING: found pointer to int where int is expected
at line 47 in file '9e748221\script.c'
WARNING: found pointer to int where int is expected
at line 47 in file '9e748221\script.c'
Well yes. There are a number of problems with your code, but I'll focus on the ones to which the warnings you presented pertain. You declare swap as an array of four pointers to functions that accept two int arguments and return an int:
int (*swap[4])(int, int)
Your function swap2() is not such a function, so a pointer to it is not of the correct type to be a member of the array. Your compiler might do you a better favor by rejecting the code altogether instead of merely emitting warnings.
Having entered a pointer to swap2() into the array anyway, over the compiler's warnings, how do you suppose the program could call that function correctly via the pointer? The type of the pointer requires function arguments to be ints; your compiler again performs the dubious service of accepting your code with only warnings instead of rejecting it.
Since the arguments in fact provided are the correct type, it might actually work on systems and under conditions where the representations of int and int * are compatible. That is no excuse, however, for writing such code.
Because pointers and ints are unchanged by the default argument promotions, one alternative would be to omit the prototype from your array declaration:
int (*swap[4])() = {swap1,swap2,swap3,swap4};
That says that each pointer points to a function that returns int and accepts a fixed but unspecified number of arguments of unspecified types. At the point of the call, the actual arguments will be subject to the default argument promotions, but that is not a problem in this case. This option does prevent the compiler from performing type checking on the arguments, but in fact you cannot do this correctly otherwise.
Your compiler might still warn about this, or could be induced to warn about it with the right options, but the resulting code nevertheless conforms and does the right thing, in the sense that it calls the pointed-to functions with the correct arguments.
To deal with the warnings first: You declare an array of functions which take int parameters. This means that swap2 is incompatible with the type of element for the array you put it in. This will generate a diagnostic.
Furthermore, when you call one of the functions in the array, the same array declaration tells the compiler that the parameters need to be ints not pointers to int. You get two diagnostics here, one for each parameter.
To fix the above all your functions need to have compatible prototypes with the element type of the array. Should it be int or int*? This brings us to the other problem.
C function arguments are always pass by value. This means that the argument is copied from the variable onto the stack (or into the argument register depending on the calling convention and argument count - for the rest of this post, I'll assume arguments are placed on the stack for simplicity's sake). If it's a literal, the literal value is put on the stack. If the values on the stack are changed by the callee no attempt is made by the caller, after the function returns, to put the new values back in the variables. The arguments are simply thrown away.
Therefore, in C, if you want to do the equivalent of call by reference, you need to pass pointers to the variables you use as arguments as per swap2. All your functions and the array should therefore use int*. Obviously, that makes one of swap1 and swap2 redundant.
The correct array definition is
int (*swap[4])(int*, int*) = {swap1, swap2, swap3, swap4};
and the definition of each function should be modified to take int* parameters. I'd resist the temptation to use int (*swap[4])() simply because it circumvents type safety. You could easily forget the & in front of an int argument when the called function is expecting a pointer which could be disastrous - the best case scenario when you do that is a seg fault.
The others have done great work explaining what the problems are. You should definitely read them first.
I wanted to actually show you a working solution for that sort of problem.
Consider the following (working) simple program :
// main.c
#include <stdio.h>
void swap1(int* aPtr, int* bPtr) {
printf("swap1 has been called.\n");
int tmp = *aPtr;
*aPtr = *bPtr;
*bPtr = tmp;
}
void swap2(int* aPtr, int* bPtr) {
printf("swap2 has been called.\n");
*aPtr += *bPtr;
*bPtr = *aPtr - *bPtr;
*aPtr -= *bPtr;
}
int main() {
int a = 1, b = 2;
printf("a is now %d, and b is %d\n\n", a, b);
// Declare and set the function table
void (*swapTbl[2])(int*, int*) = {&swap1, &swap2};
// Ask for a choice
int choice;
printf("Which swap algorithm to use? (specify '1' or '2')\n>>> ");
scanf("%d", &choice);
printf("\n");
// Swap a and b using the right function
swapTbl[choice - 1](&a, &b);
// Print the values of a and b
printf("a is now %d, and b is %d\n\n", a, b);
return 0;
}
First of, if we try to compile and execute it:
$ gcc main.c && ./a.out
a is now 1, and b is 2
Which swap algorithm to use? (specify '1' or '2')
>>> 2
swap2 has been called.
a is now 2, and b is 1
As myself and others mentioned in answers and in the comments, your functions should all have the same prototype. That means, they must take the same arguments and return the same type. I assumed you actually wanted to make a and b change, so I opted for int*, int* arguments. See #JeremyP 's answer for an explanation of why.

What happens when you call a function with return value without assigning it to any variable?

#include <stdio.h>
#include <stdlib.h>
int f(int x) {
return x;
}
int main ( int argc,char * argv[]) {
int a=4;
f(a);
printf("PASSED!\n");
return 0;
}
What happens when you call f(a) without assigning it to anything?
What happens when you call a function with return value without assigning it to any variable?
The return value of a function need not be used or assigned. It is ignored (usually quietly).
The function still executes and its side effects still occur.
Consider the 3 functions: int scanf(), int f(), and int printf(), their return values are all ignored yet the functions were still executed.
int a=4;
scanf("%d", &a);
f(a);
printf("PASSED!\n");
It is not good to ignore return values in robust code, especially scanf().
As commented by #Olaf, a warning may be enabled by some compilers.
Explicit ignoring the result of a function is sometime denoted with (void) to quiet that warning.
(void) f(a);
Using your example, we can look at how it evaluates line by line. Starting in main.
int a=4;
We now have a variable a with the value 4.
f(a);
So now the function f is called with a, which has a value of 4. So in the function f, the first parameter is named x and it just returns that parameter x.
So the evaluation of
f(a);
is just
4;
And a program like this compiles and runs perfectly fine.
int main(int argv, char *argv[]) {
1 + 1;
return 0;
}
What happens when you call f(a) without assigning it to anything?
--> Nothing at all.
What happens when you call a function (which has return value) without assigning it to anything?
-->The function will be executed, either make no sense like your case or make a lot of senses like modifying a static variable or a global variable. The return value will be ignored.
The return value will normally be stored in a register and will not fade.
It will be overwritten when the register is needed by the compiler.
If the function is inline it may be detected by the compiler that the value isn't used and ignore the value from being computed at all.

Global variable showing abrupt behavior

here is my code.
#include <stdio.h>
#define MAX(a,b) ((a)>(b)?(a):(b))
#define SZA(a) (sizeof(a)/sizeof(a[0]))
int anish=0; // global variable showing abrupt behaviour
int a[]={0,1,5,8,9,10,17,17,20,24,30};
int n= SZA(a);
int cache[100];
int road(int len)
{
anish++;
if(cache[len]!=-1)
return cache[len];
if(len<=0)
return 0;
int max=0;
int i;
for(i=1;(i<n && len>=i);i++)
{
max=MAX(max,a[i]+road(len-i));
}
return cache[len]=max;
}
void f()
{
anish=13;
}
int main()
{
int i;
for(i=0;i<=13;i++)
cache[i]=-1;
int len=10;
// f();
printf("%d %d\n",road(len),anish);
return 0;
}
In this, road() is a recursive function and I want to calculate the number of times this function is being executed. So, I am doing this via a global variable anish.
But the value of anish is not changing in this road() function, while in function f() value of anish is being modified.
Any reason for this absurd behavior?
your c code shows an outdated anish variable
succesive printf's shows different value
this has something to do with c's internals
it has something to do with this : Parameter evaluation order before a function calling in C
loki astari said:
The order that function parameters are evaluated is unspecified
behavior. (This won't make your program crash, explode, or order
pizza... unlike undefined behavior.)
The only requirement is that all parameters must be fully evaluated
before the function is called.
In
printf("%d %d\n",road(len),anish);
the order in which the arguments are evaluated is unspecified. In this case, it seems anish is evaluated before road(len), so the value passed to printf is the unmodified value.
Evaluate road(len) before calling printf and store the result in a temporary variable.
Try this instead:
int main()
{ int i;
for(i=0;i<=13;i++)
cache[i]=-1;
int len=10;
// f();
printf("%d\n",road(len));
printf("%d\n", anish);
return 0;
}
Most likely what is happening is printf() is using the value of anish before road(len) returns.
See this for the details.
If you do it like this, it'll work:
printf("%d ",road(len));
printf("%d\n",anish);
may be its because of something inside the printf definition,

Resources