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.
Related
I know that if I passed an argument like void (*func)(void *) to a variadic function, I can retrieve the argument like:
void (*func)(void *) = va_arg( args, void (*)(void) );
What if I pass something like void (** func)(void *)? What is the correct syntax to retrieve an argument of this type using va_arg?
Being frankly, your code is not standard-compliant. There is a tiny restriction for second argument of va_arg() macro:
... The parameter type shall be a type name specified such that the type
of a pointer to an object that has the specified type can be obtained
simply by postfixing a * to type. ...
According to this, notation like void (*)(void *) is unacceptable in this case. Since simple appending of * won't give you pointer to pointer to function. You may use only typedef-ed aliases:
typedef void (*func_ptr)(void *);
typedef void (**ptr_to_func_ptr)(void *);
func_ptr var1 = va_arg(ap, func_ptr);
ptr_to_func_ptr var2 = va_arg(ap, ptr_to_func_ptr);
Same as you've mentioned:
typedef void (** func_t)(void *);
func_t ppf;
va_list vl;
va_start(vl,n);
ppf = va_arg(vl, func_t);
...
To help pointer-to-function, I always use typedef as follows:
typedef void VoidFn(void *); // Function accepts void * and returns nothing.
That declares the prototype of the function as a typedef, allowing the use of the typedef elsewhere.
That way if you have this function:
void SomeFn(void *) {...}
you can declare this pointer:
VoidFn *fnPtr = &SomeFn; // A pointer to such a function.
This then makes it easier to change the prototype independently of the pointer, helping more... sophisticated constructs:
typedef void *VoidPtrFn(void *); // Function takes a void *, returning a void *
void *SomeOtherFn(void *) { ... }
VoidPtrFn *otherFnPtr = &SomeOtherFn;
VoidPtrFn **otherFnPtrPtr = &otherFnPtr;
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 *.
I started feeling comfortable with C and then I ran into type casting. If I have the following defined in an *.h file
struct data {
int value;
char *label;
};
and this in another *.h file
# define TYPE void*
How do I cast the void pointer to the struct so that I can use a variable "TYPE val" that's passed into functions? For example, if I want to utilize the value that TYPE val points to, how do I cast it so that I can pass that value to another functions?
(struct data*)pointer
will cast a pointer to void to a pointer to struct data.
Typecasting void pointer to a struct can be done in following
void *vptr;
typedef struct data
{
/* members */
} tdata;
for this we can typecast to struct
lets say u want to send this vptr as structure variable to some function
then
void function (tdata *);
main ()
{
/* here is your function which needs structure pointer
type casting void pointer to struct */
function((tdata *) vptr);
}
Note: we can typecast void pointer to any type, thats the main purpose of void pointers.
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 ;))