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 ;))
Related
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.
I'm receiving an incompatible pointer type error warning although my code functions properly. First of all, here's a simplified version of my code:
typedef struct {
int field1;
int field2;
} my_struct;
void some_function(void **data){
// do something with *data
}
int main(int argc, char *argv[]){
my_struct *ptr = malloc(sizeof(my_struct));
ptr->field1 = 5;
ptr->field2 = 17;
some_function(&ptr);
}
The my_struct type is one example, but I'm actually using multiple types, so some_func must accept void**, rather than my_struct**. Each time I call some_func in the manner above, I recieve the following warning, and yet my code functions properly.
warning: passing argument 1 of ‘my_func’ from incompatible pointer type
I'm unsure of why these types aren't compatible, and would like to remove the warning in some way. For answers, feel free to explain why this is happening and, if possible, how to remove the warning (cpp directive, maybe?). Thanks!
Use a void * parameter type.
void ** is not a generic pointer type. void * is.
void* means (effectively) "a pointer to an untyped region of memory".
void** means (effectively) "a pointer to a region of memory, which contains pointers to untyped regions of memory".
Notice how the block in the middle has a type -- an array of void*. You're passing in effectively an array of mystruct*, which is a different type. So your compiler warns you.
Similar issues occur in C++ when trying to convert Derived** to Base**; but it applies here in C as well. (void* operates like the "base class" of all pointer types) Consider a piece of code like this:
void does_things(void** outParameter)
{
*outParameter = malloc(42); // Looks fine; writing void* to void* :)
}
int main()
{
my_struct* x = /*...*/;
does_things(&myStruct); // Ut oh, tries to make x point to
// something that is *not* a my_struct
}
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 *.
If I pass a void *vptr to a function which takes a other_type *ptr as its arg, will vptr be converted automatically to other_type *? Here is the code,
typedef struct A {
//...
}A;
void bar(A *a)
{
//do something with a
}
int main()
{
A a = {..};
void *vp = &a;
bar(vp); //will vp be converted to A*?
}
Is my code safe or correct?
Yes, void* is implicitly convertible to any pointer type, and any pointer type is implicitly convertible to void*. This is why you do not need to (and should not) cast the return value of malloc, for example.
Your code will work. You can pass a void * to something expecting a struct A *. C is only weakly typed in this regard.
I have to define a 24-bit data type.I am using char[3] to represent the type. Can I typedef char[3] to type24? I tried it in a code sample. I put typedef char[3] type24; in my header file. The compiler did not complain about it. But when I defined a function void foo(type24 val) {} in my C file, it did complain. I would like to be able to define functions like type24_to_int32(type24 val) instead of type24_to_int32(char value[3]).
The typedef would be
typedef char type24[3];
However, this is probably a very bad idea, because the resulting type is an array type, but users of it won't see that it's an array type. If used as a function argument, it will be passed by reference, not by value, and the sizeof for it will then be wrong.
A better solution would be
typedef struct type24 { char x[3]; } type24;
You probably also want to be using unsigned char instead of char, since the latter has implementation-defined signedness.
You want
typedef char type24[3];
C type declarations are strange that way. You put the type exactly where the variable name would go if you were declaring a variable of that type.
From R..'s answer:
However, this is probably a very bad idea, because the resulting type
is an array type, but users of it won't see that it's an array type.
If used as a function argument, it will be passed by reference, not by
value, and the sizeof for it will then be wrong.
Users who don't see that it's an array will most likely write something like this (which fails):
#include <stdio.h>
typedef int twoInts[2];
void print(twoInts *twoIntsPtr);
void intermediate (twoInts twoIntsAppearsByValue);
int main () {
twoInts a;
a[0] = 0;
a[1] = 1;
print(&a);
intermediate(a);
return 0;
}
void intermediate(twoInts b) {
print(&b);
}
void print(twoInts *c){
printf("%d\n%d\n", (*c)[0], (*c)[1]);
}
It will compile with the following warnings:
In function ‘intermediate’:
warning: passing argument 1 of ‘print’ from incompatible pointer type [enabled by default]
print(&b);
^
note: expected ‘int (*)[2]’ but argument is of type ‘int **’
void print(twoInts *twoIntsPtr);
^
And produces the following output:
0
1
-453308976
32767
Arrays can't be passed as function parameters by value in C.
You can put the array in a struct:
typedef struct type24 {
char byte[3];
} type24;
and then pass that by value, but of course then it's less convenient to use: x.byte[0] instead of x[0].
Your function type24_to_int32(char value[3]) actually passes by pointer, not by value. It's exactly equivalent to type24_to_int32(char *value), and the 3 is ignored.
If you're happy passing by pointer, you could stick with the array and do:
type24_to_int32(const type24 *value);
This will pass a pointer-to-array, not pointer-to-first-element, so you use it as:
(*value)[0]
I'm not sure that's really a gain, since if you accidentally write value[1] then something stupid happens.
To use the array type properly as a function argument or template parameter, make a struct instead of a typedef, then add an operator[] to the struct so you can keep the array like functionality like so:
typedef struct type24 {
char& operator[](int i) { return byte[i]; }
char byte[3];
} type24;
type24 x;
x[2] = 'r';
char c = x[2];
Here's a short example of why typedef array can be confusingly inconsistent. The other answers provide a workaround.
#include <stdio.h>
typedef char type24[3];
int func(type24 a) {
type24 b;
printf("sizeof(a) is %zu\n",sizeof(a));
printf("sizeof(b) is %zu\n",sizeof(b));
return 0;
}
int main(void) {
type24 a;
return func(a);
}
This produces the output
sizeof(a) is 8
sizeof(b) is 3
because type24 as a parameter is a pointer. (In C, arrays are always passed as pointers.) The gcc8 compiler will issue a warning by default, thankfully.
Building off the accepted answer, a multi-dimensional array type, that is a fixed-length array of fixed-length arrays, can't be declared with
typedef char[M] T[N]; // wrong!
instead, the intermediate 1D array type can be declared and used as in the accepted answer:
typedef char T_t[M];
typedef T_t T[N];
or, T can be declared in a single (arguably confusing) statement:
typedef char T[N][M];
which defines a type of N arrays of M chars (be careful about the order, here).