How to traverse an array parameter as void pointer - c

I have similar "generic" procedure like qsort, which has a void pointer (pointing at an array) and also a function pointer parameter. This function should work on any type of array.
Example:
void do_something(void * array, int count, int size, void (*test)(const void*)){
int i;
for(i=0; i<count; i++){
test(array + (index * size));
}
}
This however gives me the following warning (gcc test.c -pedantic-errors):
error: pointer of type ‘void *’ used in arithmetic [-Wpedantic]
And after some research I found out it's a bad practice to use void pointers like this. (E.g. Pointer arithmetic for void pointer in C)
So how does the standard library do this kind of stuff for like qsort? Looking at this code: (http://aturing.umcs.maine.edu/~sudarshan.chawathe/200801/capstone/n/qsort.c), I see the following:
void
_quicksort (void *const pbase, size_t total_elems, size_t size,
__compar_fn_t cmp)
{
register char *base_ptr = (char *) pbase;
....
char *lo = base_ptr;
char *hi = &lo[size * (total_elems - 1)];
...
}
Are they casting to (char *) regardless of the actual type?

i asked similar question Can I do arithmetic on void * pointers in C?.
Void * arithmetic is not defined. What does it mean to add 1 to a void pointer ? Most compilers (if they allow it) treat it as incrementing by sizeof(char) ("the next byte") but warn you.
So the right thing to do is to explicitly make it do what you want -> cast to char* and increment that

Pointer arithmetic on incomplete data type void is not legal and that is what the compiler is complaining.
As you can see in the _quicksort() the pointer is a constant one so that you can't modify the address the pointer is pointing to. There is no arthmetic operation happening on the void pointer.

Making a pointer void just takes away the "context" of the pointer - That is, how the system should look at the pointer or whatever the pointer is holding.
For this reason, compilers do not do arithmetic on void pointers. In order to do pointer arithmetic, the compiler needs to know the type of the pointer such that it can do the proper conversions (if the pointer holds an int, it will not do an addition of with 32 bits or at least it will let you know something is gone awry!).
For this reason, the only way to do this is to cast the pointer to something and do it - I would not recommend it unless you know very well what the pointer is getting. Void pointers are rather very dark programming.

Related

What is the purpose of void pointers?

Why are void pointers necessary, as long as one could cast any pointer type to any pointer type, i.e.:
char b = 5;
int*a = (int*)&b;//both upcasting
or
int b = 10;
char*a = (char*)b;//and downcasting are allowed
?
Also, why there is no need for cast when using malloc/calloc/realloc ?
one could cast any pointer type to any pointer type
Not quite. void * is defined to convert any object pointer1 to void * and back again with an equivalent value. It does not need any cast.
In less common architectures, the size and range of some other pointers may be smaller than void *. Casting between other pointers type may lose necessary information.
void * provides a universal object pointer type.
void *p = any_object_pointer; // No casts required
any_object_pointer = p; // No casts required
char * could substitute for void *, except conversion to and from other object pointers requires casts.
OP's char b = 5; int*a = (int*)&b; risks undefined behavior as the alignment needs of int * may exceed char *.
1 Function pointers may be wider than void*. void * and other pointers are object pointers. C lacks a truly universal pointer type.
void pointers are really useful to create a generic API. You might think of qsort function which can be used to sort arrays of any types. void pointers can be used if the API does not know the concrete type of the pointer.
void qsort(
void *base,
size_t number,
size_t width,
int (__cdecl *compare )(const void *, const void *)
);
Regarding allocation functions, it's the same thing. The C runtime does not know the type of the effective object. But this is not a problem as user can use generic pointer void.
So void pointers are considered as generic pointers, very useful for polymorphism, that's why the C language makes casting to void optional.
"Why are void pointers necessary, as long as one could cast any pointer type".
The alloc function would then have to use common denominator such as char. But then it would be confusing to have to cast to whatever we really need. "void" just means "a bunch of bytes".

Is it legal to modify any data pointer through a void **

Is it legal to access a pointer type through a void **?
I've looked over the standards quotes on pointer aliasing but I'm still unsure on whether this is legal C or not:
int *array;
void **vp = (void**)&array;
*vp = malloc(sizeof(int)*10);
Trivial example, but it applies to a more complex situation I'm seeing.
It seems that it wouldn't be legal since I'm accessing an int * through a variable whose type is not int * or char *. I can't come to a simple conclusion on this.
Related:
Does C have a generic "pointer to a pointer" type?
C-FAQ question 4.9
No. void ** has a specific type (pointer to a pointer-to-void). I.e. the underlying type of the pointer is "pointer-to-void"
You're not storing a like-pointer value when storing a pointer-to-int. That a cast is required is a strong indicator what you're doing is not defined behavior by the standard (and it isn't). Interestingly enough, however, you can use a regular void* coming and going and it will exhibit defined behavior. In other words, this:
#include <stdio.h>
#include <stdlib.h>
int main()
{
int *array;
void *vp = &array;
int **parray = vp;
*parray = malloc(sizeof(int)*10);
}
is legitimate. Your original example won't even compile if I remove the cast and use apple llvm 4.2 (clang), due precisely to incompatible pointer types, i.e. the very subject of your question. The specific error is:
"Incompatible pointer types initializing 'void **' with an expression of type 'int **'"
and rightfully so.
Pointer to different types can have different sizes.
You can store a pointer to any type into a void * and then you can recover it back but this means simply that a void * must be large enough to hold all other pointers.
Treating a variable that is holding an int * like it's indeed a void * is instead, in general, not permitted.
Note also that doing a cast (e.g. casting to int * the result of malloc) is something completely different from treating an area of memory containing an int * like it's containing a void *. In the first case the compiler is informed of the conversion if needed, in the second instead you're providing false information to the compiler.
On X86 however they're normally the same size and you're safe if you just play with pointers to data (pointers to functions could be different, though).
About aliasing any write operation done through a void * or a char * can mutate any object so the compiler must consider aliasing as possible.
Here however in your example you're writing through a void ** (a different thing) and the compiler is free to ignore potentially aliasing effects to int *.
Your code may work on some platforms, but it is not portable. The reason is that C doesn't have a generic pointer to pointer type. In the case of void * the standard explicitly permits conversions between it and other pointer to complete/incomplete types, but this is not the case with void **. What this means is that in your code, the compiler has no way of knowing if the value of *vp was converted from any type other than void *, and therefore can not perform any conversions except the one you explicitly cast yourself.
Consider this code:
void dont_do_this(struct a_t **a, struct b_t **b)
{
void **x = (void **) a;
*x = *b;
}
The compiler will not complain about the implicit cast from b_t * to void * in the *x = *b line, even though that line is trying to put a pointer to a b_t in a place where only pointers to a_t should be put. The mistake is in fact in the previous line, which is converting "a pointer to a place where pointers to a_t can be put" to "a pointer to a place where pointers to anything can be put". This is the reason there is no implicit cast possible. For an analogous example with pointers to arithmetic types, see the C FAQ.
Your cast, then, even though it shuts the compiler warning up, is dangerous because not all pointer types may have the same internal representation/size (e.g. void ** and int *). To make your code work in all cases, you have to use an intermediate void *:
int *array;
void *varray = array;
void **vp = &varray;
*vp = malloc(sizeof(int) * 10);

Why type cast a void pointer?

Being new to C, the only practical usage I have gotten out of void pointers is for versatile functions that may store different data types in a given pointer. Therefore I did not type-cast my pointer when doing memory allocation.
I have seen some code examples that sometimes use void pointers, but they get type-cast. Why is this useful? Why not directly create desired type of pointer instead of a void?
There are two reasons for casting a void pointer to another type in C.
If you want to access something being pointed to by the pointer ( *(int*)p = 42 )
If you are actually writing code in the common subset of C and C++, rather than "real" C. See also Do I cast the result of malloc?
The reason for 1 should be obvious. Number two is because C++ disallows the implicit conversion from void* to other types, while C allows it.
You need to cast void pointers to something else if you want to dereference them, for instance you get a void pointer as a function parameter and you know for sure this is an integer:
void some_function(void * some_param) {
int some_value = *some_param; /* won't work, you can't dereference a void pointer */
}
void some_function(void * some_param) {
int some_value = *((int *) some_param); /* ok */
}

Confusion regarding a function definition in C

I found this function definition
void *func(void *param) {
}
Actually, I have a certain confusion regarding this function definition. What does void * mean in the return type of the function as well as the argument. I am a beginner in C. So please don't mind. Thank you
void *func(void *param) {
int s = (int)param;
....
}
Well looking at the above program which I found. I think it should have been
int *s = (int *)param;
isn't it? I am confused
void * means it's a pointer of no specific type, think of it as a generic pointer, unlike say int * an int pointer.
You can cast it into a different type if need be (for instance if you are going to do pointer arithmetic with the pointer).
You might find this SO question of use: Concept of void pointer in C programming
It simply means that the function func takes one parameter which is a pointer (to anything) and returns a pointer (to anything). When you use a void *, you are telling the compiler "this is a pointer, but it doesn't matter at this point what it's a pointer to".
When you want to actually use the data it's pointing to, you need to cast it to a pointer to some other type. For example, if it points to an int, you can create an int * variable and dereference that:
int *int_ptr = (int *)param;
// now (*int_ptr) is the value param is pointing to
you can think of it as a raw pointer, nothing more than an address, think about it, pointers are nothing more than address right, so they should all be of equal size, either 32 or 64 bits in most modern systems but if thats the case why do we say int * or char * or so on if they are all the same size, well thats because we need of a way to interpret the type we are pointing to, int * means when we dereference go to that address and interpret the 4 bytes as an int or char * means when we dereference go to that address and get a byte, so what happens when you dereference a void * well you get warning: dereferencing ‘void *’ pointer basically we really can't and if you do its affects are compiler dependent, the same applies when we do arithmetics on it.
So why bother using them? well I personally don't and some groups dont particularly like them, fundamentally they allow you to create fairly generic subroutines, a good example would be memset which sets a block of memory to a certain byte value, its first argument is a void * so it won't complain whether giving a char * or int * due note that it works on a per byte basis, and you need to properly calculate the total size of the array.
void *func(void *param) {
}
param is a void pointer means it is a pointer of any reference type. since a void pointer has no object type,it cannot be dereferenced unless it is case.
so void *param;
int *s=(int*)param;
here since param is an pointer variable so you will have to cast it as a pointer variable.not to a int type as you did there.
e.g.
int x;
float r;
void *p=&x;
int main()
{
*(int *)p=2;
p=&r;
*(float*)p=1.1;
}
in this example p is a void pointer. now in main method I have cast the p as a int pointer and then as a float pointer so that it can reference to first a integer and then a float.
Returning a pointer of any type. It can be of any datatype.

Pointer mismatch for actual parameter?

I have a function which creates an array of pointers. The function which allocates the memory returns the new memory pointer through a parameter passed to the function. The simplest code which can reproduce the problem is as follows:
void foo (void** new_mem, size_t bytes)
{
*new_mem = malloc(bytes);
}
int main (void)
{
int** ptr_arr; // Want to create an array of pointers
foo(&ptr_arr, sizeof(int*)*100); // Create an array size of 100
// compiler emits warning:
// 'void **' differs in levels of indirection from 'int ***'
return 0;
}
I could cast the first parameter passed to foo like so: '(void**)&ptr_arr' to get rid of the warning, however, I'm wondering: Is there a more appropriate solution?
Although there's a guaranteed conversion from int * to void *, there's no such guarantee for converting from int ** to void **. To think about why this might be, consider that an int * might actually be smaller than a void *. As a result, using a void ** pointer to walk over an array of int *s will walk the wrong stride and get the wrong data. Furthermore, there's no guarantee that int * will use the same representation as void *, only that there is a way to convert between them.
In practice, I don't know of any machines where this will fail. But it's not guaranteed by the standard.
EDIT: eek, and what everyone says about passing an int ***. But even if you pass an int **, the above still applies.
EDIT2: the comp.lang.c FAQ has an excellent discussion about this.
The problem is you're taking the address of a double pointer and passing it to a double pointer parameter. Taking the address of a value creates a pointer so you end up really with a triple pointer int*** which is why you get the error.
Casting the result to void** will technically work here although it is bordering on an abuse on the type system.
The trouble is ptr_arr is already an int **,
when you do an &ptr_arr, it will show as int *** , so what you are doing is incorrect.
So, you can just pass ptr_arr if your intention is to pass an int **
Also, I feel your code can do well with a cleanup. Your approach seems to be wrong.

Resources