C - Strange Prototype Argument - c

What's going on in this function prototype? Obviously the void parameter with some sort of typecasting is confusing...
int *my_func(my_struct *m, void (*m_op)(my_struct *v, void arg));

The second argument to the function my_func is a pointer to a function that returns no value (void), but which takes two arguments, a my_struct pointer and ... and (an invalid) void. The latter should probably be void *arg; you cannot have a variable or argument of type void. As it stands, the code should not compile.

This prototype declares a function, my_func that returns int *. It takes two arguments, the first being of type my_struct * and the second of the strange type void (*)(my_struct *, void). This means that the second argument is a pointer to a function that returns void and takes 2 arguments itself, a pointer to my_struct and void (I assume that was a typo and it takes a void *).

This little article explains how to parse C declarations in a spiral-like motion. Constructing is done in the reverse.

My suggestion - always try to split declarations into smaller ones - in that case code will be more readable. In this case you could re-write code as:
typedef struct {} my_struct;
typedef void (* m_op_function)(my_struct * v, void * arg);
int * my_func(my_struct * m, m_op_function f);
And as everybody said- it's almost 99,99% typo here regarding second parameter to m_op_function- it is possible void* - so that you can pass any pointer to it - be it (char*), (int*), (my_struct*), or anything else. Simply just cast pointer.

Related

What does this expression: void* (*fct)(void*(*)(void*), void*)?

I know that e.g.
void *(*myFuncName)(void*)
is a function pointer that takes and also returns void*.
Is this a pointer which takes 2 arguments?
A void pointer another function of that type returning void* and a void*?
I'm just guessing..
void* (*fct)(void*(*)(void*), void*);
declare fct as a pointer to a function that
returns a void *
expects its first argument is of type pointer to a function that expects a void * and returns a void * and
expects its second argument is of type void *.
void* (*fct)(void*(*)(void*), void*)
// 44444 2111 333333333333333333333333
fct (1) is a pointer (2) to a function (3*) that returns a pointer (4).
(*) The function parameters are void*(*)(void*) and void*
void*(*)(void*) a pointer to a function that takes a pointer argument and returns a pointer
void* a pointer
cdecl.org and my compiler both agree. It's a syntax error. There are more close parentheses than open ones.
A function pointer named x that returns void * and takes two parameters of type void * would look like:
void *(*x)(void *, void *);
Read to the left:
myFuncName is a pointer. What is it a pointer to?
Read to the right:
myFuncName is a pointer to a function which takes two arguments, one of which is a function pointer (with one void* argument and returning void*, similar to myFuncName), and the other one being of type *void*, returning void*. What does the function return?
Read to the left:
myFuncName is a pointer to a function which takes two arguments (see above) and returns void*
As https://stackoverflow.com/users/47453/bill-lynch pointed out, cdecl will tell you the same, as long as your syntax is correct.
Best regards
Andreas

Declaration of function pointers

To declare a function pointer using typedef, it will be something like:
typedef void (*FOO)(int i)
But normally the syntax for typedef is like:
typedef int BOOL
so why is the first one not:
typedef void (*)(int) FOO
To return a function pointer (without typedef), the syntax is as follow:
void (*foo(char c))(int)
which means foo takes in a char and returns a pointer to a function which takes an int and returns nothing. The syntax is so weird! It looks like foo takes in an int and returns nothing. The parentheses don't seem to be in the right places. If it is to return a function pointer, why is it not something like:
(void (*)(int)) foo(char c)
which is very straightforward. I am really having trouble understanding the syntax here, let alone using it. Can someone please explain what's going on here?
An integer is just:
int x;
A name for the above is given by:
typedef int x_type;
A pointer to an int is:
int *p;
It's type would be:
typedef int *p_type;
A function called foo taking a double``and returning anint` is:
int foo(double);
Defining the type of foo would be:
typedef int foo_type(double);
Now a pointer to the above should take an *, but () (function call) binds tighter than * (dereference), so parentesis:
typedef int (*ptr_to_foo_type)(double);
This might be better written:
typedef foo_type *ptr_to_foo_type;
as some suggest writing for clarity.
The idea is that the type description looks (somewhat) like its use. Badly mangled idea, given prefix/postfix operators, that much everybody agrees on. But it is now much too late to change.
Declaration syntax is based on the types of expressions, not objects. Another way of saying it is that "declaration mimics use".
Let's start with a simple pointer expression; call it iptr. iptr points to an integer value. If we want to access that value, we need to dereference iptr with the unary * operator, like so:
x = *iptr;
The expression *iptr has type int, so the declaration of iptr is written
int *iptr;
If you wanted to create a typedef for an int pointer, you would add the typedef to get
typedef int *iptr;
iptr now serves as a synonym for type "pointer to int", so you can write
iptr ip;
which declares ip as a pointer to int (as a rule, you really don't want to hide pointers in typedefs).
Now let's say you have a pointer to a function that takes two int arguments and returns an int value, call it fp. To call the function, you dereference the pointer and pass the necessary arguments to the resulting function, like so:
x = (*fp)(arg1, arg2); // C allows you to omit the * in the call, so you could
// also write it as simply x = fp(arg1, arg2), but we're
// leaving it in so the following explanation makes sense
The function call () operator has higher precedence than unary *; *fp() will be interpreted as *(fp()), which is not what we want. To dereference fp before calling the function it points to, we must explcitly group the * operator with fp.
The type of the expression (*fp)(arg1, arg2) is int, so the declaration of fp becomes
int (*fp)(int arg1, int arg2);
Let's look at your second example now: foo is a function that takes a char argument and returns a pointer to a function that takes an int argument and returns void. You'd call it as something like
(*foo(c))(x);
Again, the type of the expression (*foo(c))(x) is void, so it follows that the declaration is
void (*foo(char c))(int x);
For syntactic reasons, typedef is treated as a storage class specifier like extern or static, although it has a very different meaning. It doesn't change the structure of a declaration; it just changes how that declaration is interpreted by the compiler. Adding typedef to the above, as in
typedef void (*foo(char c))(int x);
now creates the synonym foo for the type "function returning pointer to function returning void". It's no different from how simpler type definitions like
typedef int *iptr;
behave.
1) The syntax for typedef is to take a declaration of a variable of that type and put typedef in front of it.
2) The syntax for declarations echos the syntax for actually obtaining a value of that type. See my other recent answers regarding precedence of addressing operators (including function call), such as (*twod)[3] vs *(twod)[3] C Pointers ... I'd rather not repeat it all again.

right way to define pointer to the function

everyone, I have this piece of the code:
void foo(int var, int var1)
{
printf("%d\n", var);
printf("%d\n", var1);
}
void foo_for_foo( void (*some_function)(int, int))
{
int x = 5;
some_function(x, x);
}
int main()
{
void (*ptr_foo); // <- look here
ptr_foo = &foo;
foo_for_foo(ptr_foo);
return 0;
}
does it matter how do I define pointer to function:
1) void (*ptr_foo);
2) void (*ptr_foo)(int, int);
my compiler receives both versions
thanks in advance for the explanations of the difference
The two forms are not equivalent.
void (*ptr_foo) is not a function pointer at all. It's a normal, non-function void pointer. The parentheses are superfluous and misleading. It's exactly as if you had written void* ptr_foo.
void (*ptr_foo)(int, int) is the proper way to declare a function pointer to a function taking two ints and returning void.
The only reason that this works is because in C, void pointers are implicitly convertible to any other type of pointer. That is, you can assign any other pointer to a void*, and you can assign a void* to any other pointer.
But the fact that this works in this example is essentially an accident of syntax. You cannot in general replace void (*foo)(int, int) with void (*foo).
If you try doing that with some_function in the argument list to foo_for_foo, your compiler will complain when you try to invoke some_function because it is not a function pointer.
Similarly, if your foo function happened to return an int instead of void, you would notice the problem right away. Declaring ptr_foo as int (*ptr_foo) would have resulted in an error on the statement ptr_foo = &foo because unlike void pointers, int pointers are not implicitly convertible to other pointer types.
In short, always use the second form. It is the only one that is correct in general, despite this fluky case.
The statement void (*ptr_foo); declares a variable of type void *. The function pointer is cast to this type in the statement ptr_foo = &foo; and back to a pointer to the proper function pointer type in the call to foo_for_foo. If you compile with gcc -Wall (or whatever extra paranoid settings your compiler supports) you should see a warning about this conversion.

function pointers query

what is the difference between these two below:
typedef void (*my_destructor)(void *);
typedef void (*my_destructor)(void *) my_func_ptr;
is the second one valid?
The first one declares a type called my_destructor. This type is a pointer to a function taking a parameter of type void* and returning nothing.
The second one is not valid, what are you trying to do ? If you want to declare a variable of type my_destructor, you have to do this:
typedef void (*my_destructor)(void *);
my_destructor my_func_ptr;
You are declaring a type for a pointer function.
The first one is the good one it mean you have a type named my_destructor who is a pointer to a function (*my_destructor) that take a void pointer (void *) on arguments and who return nothing (void).
Now you can use your type as if it was another type like for example char, long or whatever.

Mixed pointer, array and function type-declarations in C

A friend of mine was trying to test me on C (my strongest language is C++) and he asked me three questions which I could not answer:
Try to explain the following declarations:
1) int (*x)(int, char *, void *);
2) int (*x[10])(int, char *, void *);
3) int (**x[10])(int, char *, void *);
Can anyone explain these function declarations and explain what concepts are being used?
You need the cdecl program, which will give you a definite, correct answer to such questions. Learning to interpret such statements manually is doable and beneficial, but even so cdecl is extremely useful for checking if you have an correct answer.
prompt>cdecl
Type `help' or `?' for help
cdecl> explain int (*x)(int, char *, void *);
declare x as pointer to function (int, pointer to char, pointer to void) returning int
cdecl> explain int (*x[10])(int, char *, void *);
declare x as array 10 of pointer to function (int, pointer to char, pointer to void) returning int
cdecl> explain int (**x[10])(int, char *, void *);
declare x as array 10 of pointer to pointer to function (int, pointer to char, pointer to void) returning int
cdecl>
Well, the first one is a pointer to a function. In other words, it declares a variable "x" which points to a function of the following type:
int function(int, char*, void*);
And could be used as follows:
int myfunc(int a, char* b, void* c) {
return a;
}
void acallingfunction() {
int (*x)(int, char*, void*);
x = myfunc;
x(1, "hello", 0);
}
The second appears to be invalid syntax, but I may be wrong. If it had an asterisk before the x (such as int (*x[10])(int, char*, void*) ), it would be an array of function pointers, and would be used like a normal array:
x[3](1, "Hi there", 0);
The third is an array of pointers to function pointers, which doesn't seem practical, but is perfectly valid. An example usage might be:
void anothercaller() {
int (*x)(int, char*, void*);
int (**y)(int, char*, void*);
x = myfunc;
y = &x;
(*y)(1, "hello", 0);
}
Note that of these, the first two are relatively common. Pointers to functions are used to accomplish callbacks and various Object-Oriented programming concepts in C. An array of pointers to functions might be used for an event table, to find the appropriate callback.
Note that all of those are, in fact, valid C++ as well. ;)
Edit: I committed the atrocities of void main() apparently.
Edit 2: As Chris Lutz points out below, they really should be wrapped in typedefs. Typedefs make code containing pointers to functions MUCH clearer.
A function pointer
An array of function pointers
An array of pointers to function pointers
They are function pointers, as said above, but written rather obnoxiously (in my opinion). The way I would write them is:
typedef int (*funcptr)(int, char *, void *);
funcptr x;
funcptr x[10];
funcptr *x;
See Walt W's excellent answer for more about function pointers.
Since the syntax of C is like the one of C++ in this matter, geordi could be interesting to you. It is another good tool for teaching and learning those declarations (and other things related to C++ and sometimes, C too).
geordi: << ETYPE_DESC(x); int (*x)(int, char *, void *);
lvalue pointer to a function taking an integer, a pointer to a character, a pointer to anything, and returning an integer
geordi: << ETYPE_DESC(x); int (*x[10])(int, char *, void *);
lvalue array of 10 pointers to functions taking an integer, a pointer to a character, a pointer to anything, and returning integers
geordi: << ETYPE_DESC(x); int (**x[10])(int, char *, void *);
lvalue array of 10 pointers to pointers to functions taking an integer, a pointer to a character, a pointer to anything, and returning integers
As its page explains, it can do much more, including building a type for you
geordi: make type array of 10 pointers to functions taking an integer and returning void
void(*[10])(int)
If you know in principle how to declare things, but are unsure about just one thing, you may use parentheses:
geordi: make type ( void(int, bool) )*
void(*)(int, bool)
If you want to see how this looks like with an identifier in it, you may change the type of names, too
geordi: -c int x;
Success
geordi: make x a ( void(int, bool) )* and show
-c void (* x)(int, bool) ;
If you build up a declaration, but you are unsure about the precedence of the operators, then geordi's precedence functions can help you out
geordi: precedence *x(a, b)
*(x(a, b))

Resources