I know about typedef in C, but I got confused when I saw a declaration in the K&R book. The declaration is
typedef int (*PFI) (char *,char *)
What does it mean? What is PFI and how can we use it in our program?
Breaking it down, PFI is a pointer:
*PFI
To a function:
(*PFI)()
Which takes two arguments of type char *:
(*PFI)(char *, char *)
And returns an int:
int (*PFI)(char *, char *)
And declared as an alias of that type:
typedef int (*PFI)(char *, char *);
You could use it if you had a function that matches this pointer type, i.e:
int foo(char *x, char *y)
{
...
}
Then you can assign a pointer to the function to a variable of type PFI:
PFI f = &foo;
were you reading about pointer to functions?
If yes, then PFI is just a placeholder. It can be whatever name you give, it is just a function name. I guess it could mean "Preferred Function Interface" but that is just a guess.
so let's say you write a very crude code something like
typedef bool (*write_X_Bytes) (uint32 count, char *buffer);
then you can use it as a type in C since you used typedef in front of it like
write_X_Bytes print_line, print_word;
basically you give a prototype to user or whoever wants to use this code about parameters and return. You can checkout Linux kernel driver code for GPIO for real life usecase.
Basic rules of pointer declarations:
T *p; // p is a pointer to T
T *ap[N]; // ap is an N-element array of pointers to T
T *fp(); // fp is a function returning a pointer to T
T (*pa)[N]; // pa is a pointer to an array of T
T (*pf)(); // pf is a pointer to a function returning T
In both expressions and declarators, the subscript [] and function call () operators have higher precedence than the unary dereference * operator, so an expression or declarator like *f() is parsed as *(f()) - you are dereferencing the result of f. If you want to dereference f before calling it, you have to explicitly group the * operator with it - (*f)().
The way to read a hairy declaration is to start with the leftmost identifier and work your way out according to the rules above, applying them recursively to any function parameters.
If you have a function that uses abstract declarators in the parameter list like this one, just remember:
T * -> T *λ
T *[N] -> T *λ[N]
T (*)[N] -> T (*λ)[N]
T *() -> T *λ()
T (*)() -> T (*λ)()
where λ represents where the identifier would normally go.
So, the way to read this declaration is as
PFI -- PFI
typedef PFI -- is a typedef name for
typedef *PFI -- pointer to
typedef (*PFI) ( ) -- a function taking
typedef (*PFI) ( ) -- unnamed parameter
typedef (*PFI) ( * ) -- is a pointer to
typedef (*PFI) (char * ) -- char
typedef (*PFI) (char *, ) -- unnamed parameter
typedef (*PFI) (char *, *) -- is a pointer to
typedef (*PFI) (char *,char *) -- char
typedef int (*PFI) (char *,char *); -- returning int
In less formal terms, PFI is an alias for the type "pointer to a function taking two char * parameters and returning int".
So how would we use this?
A common use is declaring callbacks in function parameter lists:
void foo( char *foo, char *bar, PFI callback )
{
int x = callback( foo, bar );
...
}
That's a little easier to read than
void foo( char *foo, char *bar, int (*callback)(char *, char *) )
{
int x = callback( foo, bar );
...
}
It's also useful for declaring arrays or struct members:
int func1( char *x, char *y ) { ... }
int func2( char *a, char *b ) { ... }
...
struct s {
char *x;
char *y;
PFI f;
} blah = {"foo", "bar", func1};
PFI callbacks[] = { func1, func2, ... };
Again, that's a bit cleaner than writing
struct s {
char *x;
char *y;
int (*f)(char *, char *);
};
or
int (*callbacks[])(char *, char *) = { func1, func2, ... };
But...
"Being a bit cleaner" is not, by itself, sufficient reason to hide the type behind a typedef. You use a typedef to abstract away details about a type that the user of the type doesn't need to know about in order to use it.
For example, consider the FILE type in stdio.h. There is an entire API supporting the FILE type, such that you never need to know what it looks like under the hood.
In our case, however, we have to know that a PFI is a pointer to a function expecting two char * arguments and returning an int in order to use it. Using the typedef name saves a few keystrokes, but it also creates a "leaky" abstraction, since details about the type have to "leak" out to the programmer. In this case, it's honestly better to forego the typedef altogether and use the "naked" declaration.
https://cdecl.org/ says "declare PFI as pointer to function (pointer to char, pointer to char) returning int". That website didn't like the initial typedef but that makes it a type so you can you write:
PFI fp = f;
where f would have the prototype:
int f(char *, char *);
PFI just means "Pointer to a function returning int". It's a fast way to create a type that can be used quickly in code, because otherwise the syntax is complicated.
As one example, it's very useful for callback interfaces. You may want to define something like PFContext_t as a pointer to a function taking certain arguments and returning a context pointer. Then you can use the typedef in your data (if, for instance, you want to keep the pointer in a structure), and you can use the typedef in the arguments to a function called by the client, setting the callback.
Related
If I want to define a pointer variable p to point to the function foo() defined as below, what should be the exact type of p?
int *foo(void *arg)
{
...
}
It should be
typedef int *(*funtion_foo_type)(void *);
You need to have the pointer as the pointer to a function, returning an int *, accepting a void* argument. You can make it like
int * (*p) (void *);
and then, you can use
p = foo;
Bearing in mind the comment of Kyrylo Polezhaiev, the type of p is
int*(*)(void*)
To declare p, you need to insert the name at the correct point in the type:
int*(*p)(void*);
but it is generally more readable to use an alias:
typedef int*(func_t)(void*);
func_t* p;
To make it more easy you could for the function declaration
int *foo(void *arg);
define an alias named as for example Tfoo that looks the same way as the function declaration itself
typedef int *Tfoo(void *);
After that to declare a function pointer to the function is very easy. Just write
Tfoo *foo_ptr = foo;
Otherwise you could write
typedef int * (* TFoo_ptr )(void *);
Tfoo_ptr foo_ptr = foo;
Or you could write a declaration of the function pointer directly without using the typedef/
int * (* foo_ptr )(void *) = foo;
Are you talking about pointer to function?
First define a pointer to function that takes void argumenta and return int
typedef int (*Ptrtofun)(void);
Now safely can point this to your function.
Ptrtofun p;
p = &foo(void);
Now you have a ptr p to function and can easily use it ..
typedef regularly works like: typedef <type> <type_alias>. But typedefs for function pointers seems to have different structure: typedef int (*fn)(char *, char *); - there is no type alias, just a single function signature.
Here is the example code:
#include <stdio.h>
typedef void (*callback)(int);
void range(int start, int stop, callback cb) {
int i;
for (i = start; i < stop; i++) {
(*cb)(i);
}
}
void printer(int i) {
printf("%d\n", i);
}
main(int argc, int *argv[])
{
if (argc < 3) {
printf("Provide 2 arguments - start and stop!");
}
range(atoi(argv[1]), atoi(argv[2]), printer);
}
So - why typedefs for function pointers are different?
The syntax for using typedef to define a function pointer type follows the same syntax as you would use for defining function pointers.
int (*fn)(char *, char *);
Defines fn to be a pointer to a function ...
typedef int (*fn)(char *, char *);
Defines fn to be a type that is a pointer to a function ...
It works the same. You just have to look at it in a slightly different way. typedef defines your own type name by putting it in exactly the place where the identifier of your variable would go without the typedef. So
uint8_t foo;
becomes
typedef uint8_t footype;
footype foo;
edit: so "R Sahu" was a bit faster and see his example for the same principle applied to function pointers.
C declaration syntax is much more complicated than type identifier, with examples like
T (*ap)[N]; // ap is a pointer to an N-element array
T *(*f())(); // f is a function returning a pointer to
// a function returning a pointer to T
Syntactically, typedef is treated as a storage class specifier like static or extern. So you can add typedef to each of the above, giving
typedef T (*ap)[N]; // ap is an alias for type "pointer to N-element array
typedef T *(*f())(); // f is an alias for type "function returning
// pointer to function returning pointer to T"
I have two functions, each taking a pointer to a different type:
void processA(A *);
void processB(B *);
Is there a function pointer type that would be able to hold a pointer to either function without casting?
I tried to use
typedef void(*processor_t)(void*);
processor_t Ps[] = {processA, processB};
but it didn't work (compiler complains about incompatible pointer initialization).
Edit: Another part of code would iterate through the entries of Ps, without knowing the types. This code would be passing a char* as a parameter. Like this:
Ps[i](data_pointers[j]);
Edit: Thanks everyone. In the end, I will probably use something like this:
void processA(void*);
void processB(void*);
typedef void(*processor_t)(void*);
processor_t Ps[] = {processA, processB};
...
void processA(void *arg)
{
A *data = arg;
...
}
If you typedef void (*processor_t)(); then this will compile in C. This is because an empty argument list leaves the number and types of arguments to a function unspecified, so this typedef just defines a type which is "pointer to function returning void, taking an unspecified number of arguments of unspecified type."
Edit: Incidentally, you don't need the ampersands in front of the function names in the initializer list. In C, a function name in that context decays to a pointer to the function.
It works if you cast them
processor_t Ps[] = {(processor_t)processA, (processor_t)processB};
By the way, if your code is ridden with this type of things and switch's all over the place to figure out which function you need to call, you might want to take a look at object oriented programming. I personally don't like it much (especially C++...), but it does make a good job removing this kind of code with virtual inheritance.
This can be done without casts by using a union:
typedef struct A A;
typedef struct B B;
void processA(A *);
void processB(B *);
typedef union { void (*A)(A *); void (*B)(B *); } U;
U Ps[] = { {.A = processA}, {.B = processB} };
int main(void)
{
Ps[0].A(0); // 0 used for example; normally you would supply a pointer to an A.
Ps[1].B(0); // 0 used for example; normally you would supply a pointer to a B.
return 0;
}
You must call the function using the correct member name; this method only allows you to store one pointer or the other in each array element, not to perform weird function aliasing.
Another alternative is to use proxy functions that do have the type needed when calling with a parameter that is a pointer to char and that call the actual function with its proper type:
typedef struct A A;
typedef struct B B;
void processA(A *);
void processB(B *);
typedef void (*processor_t)();
void processAproxy(char *A) { processA(A); }
void processBproxy(char *B) { processB(B); }
processor_t Ps[] = { processAproxy, processBproxy };
int main(void)
{
char *a = (char *) address of some A object;
char *b = (char *) address of some B object;
Ps[0](a);
Ps[1](b);
return 0;
}
I used char * above since you stated you are using it, but I would generally prefer void *.
Since this is a void* I should be able to pass a pointer of anytype right? Why is the compiler giving me errors?
int cmp_func(void *, void *));
typedef struct word_{
char key[WORD_SIZE];
int *frequency;
} word;
Phash_table new_hash(int size, int (*hash_func)(char *), int (*cmp_func)(void *\
, void *));
int comp_function(struct word_ *word1,struct word_ *word2){
if( word1->frequency < word2->frequency){
return -1;
}
if(word1->frequency < word2->frequency){
return 1;
}
if(word1->frequency == word2->frequency){
return 0;
}
}
project4_functions.c:47:3: warning: passing argument 3 of 'new_hash' from incompatible pointer type [enabled by default]
hash.h:38:13: note: expected 'int (*)(void *, void *)' but argument is of type 'int (*)(struct word_ *, struct word_ *)'
The key is to make your compare function take void pointers as well:
int comp_function(void *a, void *b){
struct word *word1 = a;
struct word *word2 = b;
// Use word1 and word2 as before.
}
Addendum, concerning why the compiler is giving you warnings:
To quote the c99 standard which I found here
A pointer to void may be converted to or from a pointer to any incomplete or object
type. A pointer to any incomplete or object type may be converted to a pointer to void
and back again; the result shall compare equal to the original pointer.
This means that you can have code like the following, and the compiler won't issue the warning you're seeing:
void *a = NULL;
int (*f)(int a, char *b) = NULL;
a = f;
f = a;
It's tempting to extrapolate that this means the following will also work (after all, we're just substituting "void*" with "struct foo*", right?)
int (*f1)(void*, void*);
int (*f2)(struct foo*, struct foo*);
f1 = f2;
However, this generates your warning since it is not trying to assign a pointer type to a pointer to void (or vice-versa) as is allowed by the standard. Instead it is trying to assign a value of type int (*)(struct foo*, struct foo*) to a variable of type int (*)(void*, void*).
Of course, you could try to make the compiler happy with an explicit cast, which convinces the compiler that you must know what you're doing. But in doing so you lose the privilege and safety of getting these warnings even when invoking "iffy" behavior.
Your question does not match your code. Your code does not pass a structure pointer as a void pointer. It is passing one function pointer as another. The function pointers are not compatible, hence the error.
It is legal to pass a structure pointer where a void pointer is expected because a structure pointer can be implicitly converted to a void pointer. It is not required to be representationally identical to a void pointer. (There are some machines where structure pointers are not the same size as a void pointer, for example.)
By analogy consider the case of passing an int when a long is expected. This is legal because there is an implicit conversion, but that doesn't meant that a function accepting int is interchangeable with function accepting long.
You need to cast the function pointer since your function prototype does not match the one the function expects:
typedef int (cmp_f)(void *, void *));
new_hash(..., ..., (cmp_f*)cmp_func_p);
Of course that typedef is not necessary, but it makes your code much more readable than without (you usually only do it without that typedef in exams where you are not allowed to use typedef for this purpose ;))
I am new to C, and this typedef looks a little bit strange to me. Can someone explain what it does?
typedef void (*alpm_cb_log)(alpm_loglevel_t, const char *, va_list);
It is in a header file.
You can use cdecl.org : http://cdecl.ridiculousfish.com/?q=void+%28*alpm_cb_log%29%28alpm_loglevel_t%2C+const+char+*%2C+va_list%29+
It says:
declare alpm_cb_log as pointer to function (alpm_loglevel_t, pointer to const char, va_list) returning void
in this case, it is a typedef, not a declaration.
A Simple example.
Declaration:
typedef int myint.
Use:
myint number = 7;
myint is a synonym of int.
your example
typedef void (*alpm_cb_log)(alpm_loglevel_t, const char *, va_list);
this is a pointer to a function
(*alpm_cb_log)
The arguments are
(alpm_loglevel_t, const char *, va_list)
and does not return anything.
void
The general rule with the use of typedef is to write out a declaration as if
you were declaring variables of the types that you want
It defines alpm_cb_log to be a type for a pointer to a function that takes the arguments alpm_loglevel_t, const char *, va_list and returns void.
These do look weird if you've never seen them before. It's a typedef alpm_cb_log for a pointer to a function returning void, taking two or more arguments: an alpm_loglevel_t, a const char *, and a variable argument list.
it creates the alais alpm_cb_log which is a pointer to a function that returns void and takes three paramaters. 1. a alpm_loglevel_t 2. const char *. 3 a varaibale argument list.