I was wondering if we can create a generic function pointer, which would point to a function with any return type in C. I tried it through this code:
typedef void (*func_ptr)(int, int);
int func1(int a, int b) {
return a * b;
}
int func2(int a, int b) {
return a + b;
}
int main() {
func_ptr ptr1, ptr2;
ptr1 = func1;
ptr2 = func2;
printf("Func1: %d\n", *(int *)(*ptr1)(4, 5));
printf("Func2: %d\n", *(int *)(*ptr2)(4, 5));
return 0;
}
If the func_ptr was of type int, the code would work. But what is wrong with this approach? Why can't we assign void * pointer to integer functions?
If the func_ptr was of type int, the code would work
More precisely: if the func_ptr type definition specified a return type of int, the initialization code would be correct, but the invocation would still be invalid because the *(int *) cannot be applied to the void return value and invoking the function with a prototype different from its calling convention has undefined behavior anyway. func_ptr should be cast as ((int(*)(int, int))func_ptr) for the call to be correct.
There is no such thing as a generic function pointer, but a function taking no arguments and returning void is a close as can be. Functions with different prototypes can be stored into incompatible function pointers as long as you use a proper cast and the pointer must be cast back to the exact prototype of the function it points to at the call sites. This is possible for C, but more tricky for C++.
Beware that function call is a postfix operation, so it binds stronger than prefix operations such as a cast: (int(*)(int, int))func_ptr(3, 4) does not work. You must write:
((int(*)(int, int))func_ptr)(3, 4)
Here is a modified version:
#include <stdio.h>
// define a generic function pointer of no arguments with no return value
typedef void (*func_ptr)(void);
// actual function type: function of taking 2 ints, returning an int
typedef int (*func_of_int_int_retuning_int)(int, int);
int func1(int a, int b) {
return a * b;
}
int func2(int a, int b) {
return a + b;
}
int main() {
func_ptr ptr1, ptr2;
// use explicit casts for assignment (with or without the typedef)
ptr1 = (func_ptr)func1;
ptr2 = (void (*)(void))func2;
// at call sites, the function pointer must be cast back to the actual
// type for invocation with arguments and handling of return value
// again you can use a typedef or not
printf("Func1: %d\n", ((int (*)(int, int))ptr1)(4, 5));
printf("Func2: %d\n", ((func_of_int_int_retuning_int)ptr2)(4, 5));
return 0;
}
You are allowed to convert between different function pointers, but you are not allowed to call a function pointer unless it's compatible with the pointed-to type. You can force the assignment to compile by using a cast (which will get you a warning), but as soon as you try to call ptr1 or ptr2 you get Undefined Behavior.
You can call them if you first convert them back to the correct function type. This is correct:
typedef void (*func_ptr) (int, int); // literally any function type would work
typedef int (*real_func_ptr) (int, int);
int func1(int a, int b) { return a * b; }
int func2(int a, int b) { return a + b; }
int main() {
func_ptr ptr1, ptr2;
ptr1 = (func_ptr) func1;
ptr2 = (func_ptr) func2;
int a = ((real_func_ptr)ptr1)(4, 5);
int b = ((real_func_ptr)ptr2)(4, 5);
return a + b;
}
A few more points about your post:
I see this a lot, where students say "void function" and "int function", as if the function type is its return type. This is wrong and very misleading. The function type is: "function taking two arguments of type int and returning int" (aka int (int, int))
your typedef is: pointer to function taking 2 int arguments and returning void. It's not returning void *.
There is no generic function pointer type similar to void* for object pointers. However, the C standard actually guarantees that we can convert between any two function pointers and back, as long as we call the function through the correct kind of function pointer. This means that any function pointer type can actually be used as a generic function pointer type.
There are many problems on these lines: *(int *)(*ptr1)(4, 5).
You may not call ptr1 since it is of type void(*)(int,int) but it points at a function of type int(*))(int, int). You need to cast back to the correct type before calling. (A separate variable like an enum might be used to keep track of which type the pointer actually points at.)
Either way the *(int *) cast would just cast the result after the function call, so it doesn't do what you want.
Generic programming with function pointers generally involves deciding a certain function type to use as template, then implement all functions accordingly.
Or we can use _Generic inside a macro to sort out the types at compile-time, like for example this:
#define func(x,y) \
_Generic((x), int: _Generic((y), int: int_func, default: 0), \
char*: _Generic((y), char*: string_func, default: 0) ) (x,y)
int main (void)
{
printf("Func1: %d\n", func(4,5));
printf("Func2: %s\n", func("hello","world"));
}
Related
int main()
{
int b = 12;
void *ptr = &b;
printf("%d", *ptr);
return 0;
}
I expected for this code to print 12, but it does not.
if instead of void pointer, we define int pointer it would work.
I wanted to know how can we use void pointer and print the address allocated to it and the amount saved in it?
Dereferencing a void * doesn't make sense because it has no way of knowing the type of the memory it points to.
You would need to cast to pointer to a int * and then dereference it.
printf("%d", *((int *)ptr));
void pointers cannot be dereferenced.it will give this warning
Compiler Error: 'void' is not a pointer-to-object type*
so, you have to do it like this.
#include<stdio.h>
int main()
{
int b = 12;
void *ptr = &b;
printf("%d", *(int *)ptr);
return 0;
}
If p has type void *, then the expression *p has type void, which means "no value". You can't pass a void expression to printf for the %d conversion specifier (or any other conversion specifier).
In order to dereference a void *, you must first convert it to a pointer of the appropriate type. You can do it with a cast:
printf( "%d\n", *(int *) ptr );
or assign it to a pointer of the appropriate type:
int *p = ptr;
printf( "%d\n", *p );
The rules around void pointers are special such that they can be assigned to other pointer types without an explicit cast - this allows them to be used as a "generic" pointer type. However, you cannot directly examine the thing a void pointer points to.
A schoolbook example of when void pointers are useful is qsort.
This is the signature:
void qsort(void *base,
size_t nitems,
size_t size,
int (*compar)(const void *, const void*)
);
base is just a pointer to the first element. The reason it's a void pointer is because qsort can be used for any list, regardless of type. nitems is number of items (doh) in the list, and size is the size of each element. Nothing strange so far.
But it does also take a fourth argument, which is a function pointer. You're supposed to write a custom compare function and pass a pointer to this function. This is what makes qsort able to sort any list. But since it's supposed to be generic, it takes two void pointers as argument. Here is an example of such a compare function, which is a bit bloated for clarity:
int cmpfloat(const void *a, const void *b) {
const float *aa = (float*) a;
const float *bb = (float*) b;
if(*aa == *bb) {
return 0;
} else if(*aa > *bb) {
return 1;
} else {
return -1;
}
}
Pretty clear what is going on. It returns positive number if a>b, zero if they are equal and negative if b>a, which is the requirements. In reality, I'd just write it like this:
int cmpfloat(const void *a, const void *b) {
return *(float*)a - *(float*)b;
}
What you do with this is something like:
float arr[5] = {5.1, 3.4, 8.9, 3.4, 1.3};
qsort(arr, 5, sizeof *arr, cmpfloat);
Maybe it's not completely accurate to say that void pointers are used instead of templates, generic functions, overloaded functions and such, but they have similarities.
Why do i need to remove the function pointer casting to use the function as shown below ?
This Compiles:
#include <stdio.h>
int print_int(int i){
printf("%d", i);
return i;
}
typedef int (*print_int_func) (int);
int main(){
void** p = malloc(1*sizeof(print_int_func*));
p[0] = (print_int_func*)print_int;
((print_int_func)p[0])(2); // This Compiles
((print_int_func*)p[0])(2); // This does NOT
return 0;
}
The declaration typedef int (*print_int_func) (int); declares print_int_func to be a pointer to a specific type of function. So (print_int_func)p[0] casts p[0] to such a pointer to a function, but (print_int_func*)p[0] casts p[0] to a pointer to a pointer to a function. Thus, the result is a pointer to an object (that object being a pointer to a function). Since it is an object, not a function (or pointer to a function), it cannot be called like a function.
Additionally, avoid using void * for pointers to functions. void * is a pointer to an object, and the C standard does not define conversions between pointers to objects and pointers to functions. To create a “generic” pointer to a function, simply choose any function type and use a pointer to that type:
Convert to the chosen type when storing the pointer.
Convert to the actual function type when calling the function type.
For example, you can declare an arbitrary type:
typedef void (*CommonFunctionPointer)(void);
and make an array of them:
CommonFunctionPointer *p = malloc(N * sizeof *p);,
and then you can store any function pointer in the array:
p[i] = (CommonFunctionPointer) print_int;
and use a pointer from the array by casting it back to its correct type:
((int (*)(int)) p[i])(2);.
I am learning some of the basics of C, and am currently stepping my way through arrays and more specifically how passing by reference works. When the below code is run it returns 10 22. When I read through the code however, based on the last command it seems as though the variable a should return 22 instead of 10 (meaning the full output would be 22 22 instead of 10 22). Why would the variable a not update to 22 in this code?
#include <stdio.h>
void set_array(int array[4]);
void set_int(int x);
int main(void)
{
int a = 10;
int b[4] = { 0, 1, 2, 3 };
set_int(a);
set_array(b);
printf("%d %d\n", a, b[0]);
}
void set_array(int array[4])
{
array[0] = 22;
}
void set_int(int x)
{
x = 22;
}
Arrays are [loosely] "pass by reference". Actually, the array "decays" into an int *.
But, scalars are "pass by value".
In set_int, you set the function scoped copy of x but do not return it to the caller.
Here's the refactored code, with a "call by reference" example:
#include <stdio.h>
void
set_array(int array[4])
{
array[0] = 22;
}
int
set_int(int x)
{
x = 22;
return x;
}
void
set_int_byptr(int *x)
{
*x = 37;
}
int
main(void)
{
int a = 10;
int b[4] = { 0, 1, 2, 3 };
int c = 4;
#if 0
set_int(a);
#else
a = set_int(a);
#endif
set_array(b);
set_int_byptr(&c);
printf("a=%d b=%d c=%d\n", a, b[0], c);
return 0;
}
In C if you want to modify variable passed to function you need to pass the pointer to it:
examples:
int setval(int *obj, int value)
{
*obj = val;
return val;
}
void usage()
{
int x;
setval(&x, 22);
}
void *setpointer(void **ptr, size_t size)
{
*ptr = malloc(size);
return *ptr;
}
void usage1()
{
int *array;
setpointer(&array, 200*sizeof(*array));
}
First we need to get this out of the way, because I honestly believe it will make things less confusing - C does not pass any function arguments by reference, ever. C passes all function arguments by value. Sometimes, those values are pointers. This is not the same thing as pass-by-reference.
Among other things, pass-by-value means that any changes to a formal parameter are not reflected in the actual parameter. In your set_int function, x is a distinct object from a, and any changes to x do not affect a.
If we want a function to modify the value in a parameter, we must pass a pointer to that parameter:
void set_int( int *x )
{
*x = 22; // writes a new value to the thing x points to
}
int main( void )
{
int a = 10;
set_int( &a ); // foo writes a new value to a
return 0;
}
In the above code, we want the function set_int to update the variable a, so we must pass a pointer to a to the function.
x == &a // int * == int *
*x == a // int == int
Thus, writing a new value to the expression *x in set_int is the same as writing a new value to a in main. Any change to x itself is local to set_int.
Things get confusing when we add arrays to the mix. An array is not a pointer; however, unless it is the operand of the sizeof or unary & operators, or is a string literal used to initialize a character array in a declaration, an expression of type "N-element array of T" will be converted ("decay") to an expression of type "pointer to T" and the value of the expression will be the address of the first element.
When you call set_array(b), the expression b "decays" from type "4-element array of int" (int [4]) to type "pointer to int" (int *), and the value of the expression is the same as &b[0].
Here's another confusing thing - in a function parameter declaration, array declarations of type T a[N] and T a[] are interpreted as T *a - a is a pointer to T, not an array of T. So your prototype
void set_array(int b[4])
is interpreted as
void set_array(int *b)
and what it receives is a pointer to the first element. As a practical matter, this means that any changes to array[i] in set_array are reflected in b, but this is fallout from how C specifically treats array expressions, not a difference in parameter passing mechanisms. The argument is still being passed by value, it's just that the argument is a pointer value that's the result of a well-defined conversion operation on array expressions.
You are doing 2 things over here:
1) Pass by value:
the function set_int(), its parameter is passed simply, without any address, which means it is pass by value, and any change made by this function set_int() will not be reflected in the calling function.
2) Pass by reference:
However, in the case of set_array(b), you are passing the array to the called function, and its base address will be passed (Means address of first element of b, that is &b[0]), hence this is pass by reference and any change is made to this value will be reflected in the calling function
which is the reason 22 is updated for b, but 22 didn't get update for a
This code is practice code for pointers. But I am not understanding the (int**)&p; means in this code.
void fun(void *p);
int i;
int main()
{
void *vptr;
vptr = &i;
fun(vptr);
return 0;
}
void fun(void *p)
{
int **q;
q = (int**)&p;
printf("%d\n", **q);
}
Please elaborate how it is evaluated.
It's a type cast, that interprets the value of &p, which has type void **, as instead having type int ** which is the type of the variable the value is stored in.
The cast is necessary, since void ** is not the same as void * and does not automatically convert to/from other (data) pointer types. This can be confusing.
&p being of type void**, is being casted to type of int** which is to be assigned to q.
SIDE-NOTE : "Any pointer can be assigned to a pointer to void. It can then be cast back to its original
pointer type. When this happens the value will be equal to the original pointer value."
Be careful when using pointers to void. If you cast an arbitrary
pointer to a pointer to void, there is nothing preventing you from
casting it to a different pointer type.
Here is the code which i got confused with.It would be great help if someone corrected this code?
int (*(x)())[2];
int main()
{
int (*(*y)())[2]=x;
x();
return 0;
}
int (*(x)())[2]
{
int **str;
str=(int*)malloc(sizeof(int)*2);
return str;
}
How to assign an array of pointers when returned by x?is using malloc only solution?
Thanks in advance
It's not entirely clear what you're trying to accomplish, so I'll cover more than one possibility.
First of all, a refresher on how to read and write complicated declarations in C:
Remember that () and [] have higher precedence than unary *, so *a[] is an array of pointers, while (*a)[] is a pointer to an array; similarly, *f() is a function returning a pointer, while (*f)() is a pointer to a function.
When you're trying to read a hairy declaration, start with the leftmost identifier and work your way out, remembering the rule above. Thus,
int (*(x)())[2];
reads as
x -- x
(x) -- x
(x)() -- is a function
*(x)() -- returning a pointer
(*(x)())[2] -- to a 2-element array
int (*(x)())[2] -- of int
In this case, the parens immediately surrounding x are redundant, and can be removed: int (*x())[2];.
Here's how such a function could be written and used:
int (*x())[2]
{
int (*arr)[2] = malloc(sizeof *arr); // alternately, you could simply write
return arr; // return malloc(sizeof (int [2]));
} // type of *arr == int [2]
int main(void)
{
int (*p)[2] = NULL; // alternately, you could write
... // int (*p)[2] = x();
p = x();
...
free(p);
}
Notice that the declarations of arr, p, and x() all look the same -- they all fit the pattern int (*_)[2];. THIS IS IMPORTANT. If you declare one thing as T (*p)[N] and another thing as T **q, then their types are different and may not be compatible. A pointer to an array of T is a different type than a pointer to a pointer to T.
If your goal is to create an array of pointers to functions returning int, then your types would look like int (*f[2])();, which reads as
f -- f
f[2] -- is a 2-element array
*f[2] -- of pointers
(*f[2])() -- to functions
int (*f[2])(); -- returning int
That would look something like the following:
int foo() {...}
int bar() {...}
int main(void)
{
int (*f[2])() = {foo, bar};
...
}
If you want a function that returns f, that's a little trickier. C functions cannot return array types; they can only return pointers to arrays, so your function declaration would be built up as
g -- g
g() -- is a function
*g() -- returning a pointer
(*g())[2] -- to a 2-element array
*(*g())[2] -- of pointers
(*(*g())[2])() -- to functions
int (*(*g())[2])() -- returning int
And such a beastie would be used something like this:
int foo() {...}
int bar() {...}
int (*(*g())[2])()
{
int (*(*f)[2])() = malloc(sizeof *f);
(*f)[0] = foo; // the type of the *expressions* foo and bar
(*f)[1] = bar; // is `int (*)()`, or pointer to function
return f; // returning int
}
int main(void)
{
int (*(*p)[2])();
int x, y;
...
p = g();
x = (*(*p)[0])();
y = (*(*p)[1])();
...
free(p);
...
}
Note that you can also build up hairy declarations from the outside in, using a substitution method. So,
int x(); -- x is a function returning int
int (*p)(); -- replace x with (*p) to get a pointer to a function
returning int
int (*a[2])(); -- replace p with a[2] to get an array of pointers
to functions returning int
int (*(*q)[2])(); -- replace a with (*q) to get a pointer to an array
of pointers to functions returning int
int (*(*g())[2])(); -- replace q with g() to get a function returning
a pointer to an array of pointers to functions
returning int.
Same result, different path. I prefer the first method, but either one should work.
Many people recommend using typedef to make things easier to read:
typedef int ifunc(); // ifunc is a synonym for "function returning int"
typedef ifunc *pifunc; // pifunc is a synonym for "pointer to function
// returning int
typedef pifunc farr[2]; // farr is a synonym for "2-element array of
// pointer to function returning int
typedef farr *pfarr; // pfarr is a synonym for "pointer to 2-element
// array of pointer to function returning int
pfarr g()
{
pfarr f = malloc(sizeof *f);
(*f)[0] = foo;
(*f)[1] = bar;
return f;
}
int main(void)
{
pfarr p = g();
int x, y;
x = (*(*p)[0])();
y = (*(*p)[1])();
...
}
Yes, the declarations are easier to read, but there's no connection between the declaration of pand the expression (*(*p)[1])(). You'd have to grovel back through all the typedefs to understand why that expression is written the way it is, building up a mental map for each typedef.
Yes, declarations like int (*(*g())[2])() are designed to make your eyes glaze over, hiding all that behind a typedef makes the situation worse IMO.
Don't understand what you want to do, maybe this can help
#include<stdio.h> // printf
#include<stdlib.h> // malloc free
int *x(); // forward declaration because used before definition
int main() {
int *y=x(); // y is a pointer on int
printf ("%d %d\n", y[0], y[1]);
free(y); // must call free because dynamic allocation
return 0;
}
int *x() {
int *res;
res=(int*)malloc(sizeof(int)*2); // dynamic allocation of an array of two int
// should check res != NULL
res[0]=10;
res[1]=20;
return res;
}
This following code will give you an array of pointers to functions, and standard procedures for assigning, passing of arrays applies.
#include <stdio.h>
#include <stdlib.h>
typedef int (*XFunc())();
XFunc *x[2]; /* array of XFunc pointers */
int f1()
{
printf("1\n");
return 1;
}
int f2()
{
printf("2\n");
return 2;
}
int main()
{
x[0] = (XFunc*)f1;
x[1] = (XFunc*)f2;
x[0]();
x[1]();
return 0;
}
The pointer x above will point to the first element in the (fixed) array, this pointer-value is the value that will be assigned to another variable.