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
}
Related
I am having problems doing the following scenario. I have a function which comes as:
void testing(mystruct str**) {
pthread threads[5];
for(int i = 0; i < 5; i++) {
pthread_create(&thread[i], NULL, process, (void)&(*str)); //not really sure how to pass this here
}
}
void * process(void *arg) {
struct mystruct **value = arg; //probably wrong but it compiles, then blows up some where else because its not really the value that was original passed.
}
I am new to C and as far as I understand this is whats its doing,
I get a double pointer
to pass it to the fuction I would pass it casted as void because thats what the function accepts and also with the address of the str pointer (or would it be the address of the pointer to pointer? &str ?)
*then when obtaining it on the other side, I set it, i tried casting it to the struct but that did not go well either as such:
struct mystruct **value = *(mystruct *)arg;
but i get "dereferencing pointer to incomplete type"
any help understanding this would be much appreciated.
You should be able to pass on the pointer as-is, since every object pointer type in C can be implicitly converted to/from void*. Still, it is more correct to de-reference the pointer one level. That is:
pthread_create(&thread[i], NULL, process, *str);
IMPORTANT: This assumes that str points at a variable which will not go out of scope while the thread is executing! Passing on pointers to local variables to threads is a common source of bugs.
From there on, your thread callback should do something like this:
void * process(void *arg) {
struct mystruct* ms = arg;
struct mystruct** ptr_ms = &arg;
However, the error "dereferencing pointer to incomplete type" simply means that the struct definition isn't visible to the thread, causing the struct type to get treated as incomplete. So the issue might as well be a missing #include.
I am editing someone else's code and trying to make sense of it. The function passes in a parameter void **dst_val. I am not great with pointers. I have looked at all of the remotely relevant posts on stack overflow and didn't find what I am looking for.
I have a struct:
typedef struct {
u_int img_out_len;
char *img_out_val;
} img_out;
I declare a pointer to a struct:
img_out *clnt_res;
and allocate memory for it.
Now, where I'm confused. I need to set void **dst_val to point to the img_out_val pointer inside the pointer to the struct, and I can't figure out the syntax. Why are these incorrect, and what is correct?
dst_val = (void *)(*clnt_res).img_out_val; //wrong
dst_val = (void **)clnt_res->img_out_val; //wrong
I should also note that img_out_val points to data for a binary file.
Edit:
Since the function passes in void **dst_val, I need that to point to the data for the binary when the function returns.
If frslm's anser is not good enough, you could also try
&(void*)clnt_res->img_out_val;
Since clnt_res->img_out_val gives you a char *, you need to get the address of that (to end up with a char **) before casting it as a void **:
(void **)&clnt_res->img_out_val;
Assuming you had to call
void foo(void ** ppv);
then to get around any casting questions/issues do it like this:
{
void * pv = &clnt_res->img_out_val;
foo(&pv);
}
or even shorter:
{
foo(&((void*){&clnt_res->img_out_val}));
}
Please note that the above void* does not indicate a cast but defines a compound literal of type void*.
I have a struct which looks somewhat like this:
struct Data
{
int a;
float b;
char *c;
int (*read)(struct Data *data, int arg1);
int (*write)(struct Data *data, int arg1, int arg2);
int (*update)(struct Data *data, int arg1, int arg2, int arg3);
int (*erase)(struct Data *data, int arg1);
/* ... */
}
The ... means that there is bunch of other function pointers smiliar to above (that is, they all return an int and take pointer to Data as first argument, but other arguments may differ).
Let's say there are 20 function pointers total. In a special function DataInit(), I assign functions to them, like this:
Data->read = readA;
Data->write = writeA;
/* readA() and writeA() are functions defined elsewhere in the code, with argument lists same as corresponding function pointers */
Now I have to do the same for another object of type Data, which differs in a way that it's "read-only"; it basically means that from those 20 function pointers 15 has to be assigned such that after invoking them they should return error code NOT_SUPPORTED. The rest stay the same (for example, readA() is assigned to function pointer (*read) like above).
I was wondering if there's a way to do it without implementing a function for each pointer (for example, updateB() that takes three arguments and its body is just return NOT_SUPPORTED). Unfortunately, I cannot just set them to NULL.
I was thinking about preprocessor macros but it's black magic to me, honestly.
No, you may not cast a function pointer to a function pointer of different type (or even worse, to a different pointer type). This causes undefined behavior in the C standard for a good reason.
There are currently architectures out there where this isn't just a theoretical problem that everyone gets away with, but it can actually crash your program in unexpected ways. Read this blog post if you want details.
I don't know whether my suggestion is legal or not, but I want to suggest this:
int data_not_supported_(struct Data *thiz, ...)
{
return NOT_SUPPORTED;
}
And there might be no problem if your compiler uses cdecl calling convention, where the number of argument doesn't affect on the caller.
Yes, you can use a single function
int unsupported() {
return NOT_SUPPORTED;
}
and cast to correct the function pointer type when initializing your struct:
Data->write = (int (*)(struct Data *, int, int))unsupported;
These casts are ugly, so it's more readable to have a typedef for each function:
typedef int
(*write_t)(struct Data *, int, int);
And then:
Data->write = (write_t)unsupported;
As mentioned, function pointer casts will most likely result in undefined behavior on most systems.
A feasible solution to the problem is this:
typedef int func_t (struct Data* this, void* arg);
struct Data
{
int a;
float b;
char* c;
func_t* read;
func_t* write;
...
};
// later on in the code:
int update_function (struct Data* this, void* arg)
{
struct my_type* m = (struct my_type*)arg;
// use m
}
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 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).