would it be OK if the function was: void memcpy(char* dst, const char* src, size_t size)?
What is the advantage of using void pointers in memcpy()?
Before the void data type was added in the 1989 standard, that was how functions like memcpy were designed. char * was the closest thing to a "generic" pointer at the time.
The problem is that if memcpy still used char * arguments and you wanted to call memcpy on a target that wasn't an array of char, you would have to explicitly cast the pointer value:
int foo[N];
int bar[N];
...
memcpy( (char *) foo, (const char *) bar, N * sizeof *foo );
because you can't assign pointers of one type to another type without a cast. This wasn't (as much of) a problem in pre-ANSI C because you didn't have function prototypes; that is, the compiler didn't check that the number and types of arguments in the function call matched the definition, but it's definitely an issue now.
However, unlike other object pointer types, you can assign any T * value to void * and back again without needing the cast, so the memcpy call can be written as
memcpy( foo, bar, N * sizeof *foo );
I remember the pre-standardization days (although I was still in college). Casting gymnastics weren't fun. Embrace the void * type, because it is saving you some heartburn.
would it be OK if the function was: void memcpy(char* dst, const char* src, size_t size)?
Yes, because pointers can be casted to another pointer type.
What is the advantage of using void pointer in memcpy()?
Avoiding a cast to the destination pointer type.
What is the advantage of using void pointer in memcpy()?
A void pointer is a generic pointer, so it can accept a pointer to any type.
Related
I came across int safe_alloc_realloc_n (void *ptrptr, size_t size, size_t count) function, at Github/scratchpadRepos/gnulib, which is actually an older version of the official gnulib,
In that function, I found *(void **)ptrptr weird,
With or without the cast, it contains a memory address, so is there any point of casting here,
Why gnulib uses *(void **) ptrptr instead of proper, and without cast, usage
The argument is a void *, doing *ptrptr would try to assign to void. void is a void, you can't assign to it.
On POSIX systems you can cheat, all pointers have the same alignment and size. You can do int *a; *(void **)&a = some_value;, although such code is very invalid according to C language.
The function takes a generic pointer void * and then assigns to the pointer, so that you can int *a; safe_alloc_realloc_c(&a, ...) pass a pointer to any pointer type. Otherwise you would have to create a separate function for every type safe_alloc_realloc_c_int(int **, ...) safe_alloc_realloc_c_char(char **, ...) etc.
Have same functionality,
No. malloc allocates memory. new allocates the memory and creates an object, calling object constructor and starting object lifetime.
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".
I often see void pointers being cast back and forth with other types of pointers and wonder why, I see that malloc() returns a void pointer that needs to be cast before used also.
I am very new to C and come from Python so pointers are a very new concept to wrap my head around.
Is the purpose of the void * pointer to offer some "dynamic" typing?
Take this code as example, is it valid code?
struct GenericStruct{
void *ptr;
};
// use void pointer to store an arbitrary type?
void store(struct GenericStruct *strct, int *myarr){
strct->ptr = (void *) myarr;
}
// use void pointer to load an arbitrary type as int*?
int *load(struct GenericStruct *strct){
return (int *) strct->ptr;
}
The purpose of a void * is to provide a welcome exception to some of C's typing rules. With the exception of void *, you cannot assign a pointer value of one type to an object of a different pointer type without a cast - for example, you cannot write
int p = 10;
double *q = &p; // BZZT - cannot assign an int * value to a double *
When assigning to pointers of different types, you have to explicitly cast to the target type:
int p = 10;
double *q = (double *) &p; // convert the pointer to p to the right type before assigning to q
except for a void *:
int p = 10;
void *q = &p; // no cast required here.
In the old days of K&R C, char * was used as a "generic" pointer type1 - the memory allocation functions malloc/calloc/realloc all returned char *, the callback functions for qsort and bsearch took char * arguments, etc., but because you couldn't directly assign different pointer types, you had to add an explicit cast (if the target wasn't a char *, anyway):
int *mem = (int *) malloc( N * sizeof *mem );
Using explicit casts everywhere was a bit painful.
The 1989/1990 standard (C89/C90) introduced the void data type - it's a data type that cannot store any values. An expression of type void is evaluated only for its side effects (if any)2. A special rule was created for the void * type such that a value of that type can be assigned to/from any other pointer type without need of an explicit cast, which made it the new "generic" pointer type. malloc/calloc/realloc were all changed to return void *, qsort and bsearch callbacks now take void * arguments instead of char *, and now things are a bit cleaner:
int *mem = malloc( sizeof *mem * N );
You cannot dereference a void * - in our example above, where q has type void *, we cannot get at the value of p without a cast:
printf( "p = %d\n", *(int *)q );
Note that C++ is different in this regard - C++ does not treat void * specially, and requires an explicit cast to assign to different pointer types. That's because C++ provides overloading mechanisms that C doesn't.
Every object type should be mappable to an array of char.
In K&R C, all functions had to return a value - if you didn't explicitly type the function, the compiler assumed it returned int. This made it difficult to determine which functions were actually meant to return a value vs. functions that only had side effects. The void type was handy for typing functions that weren't meant to return a value.
C suffers from the absence of function overloading. So most C "generic" functions as for example qsort or bsearch use pointers to void * that to be able to deal with objects of different types.
In C you need not to cast a pointer of any type to a pointer of the type void *. And a pointer of any type can be assigned with a pointer of the type void * without casting.
So in C the functions from your code snippet can be rewritten like
void store(struct GenericStruct *strct, int *myarr){
strct->ptr = myarr;
}
int *load(struct GenericStruct *strct){
return strct->ptr;
}
Is the purpose of the void * pointer to offer some "dynamic" typing?
No, because C has no dynamic typing. But your title is about right, on the other hand -- void * serves roughly as a generic pointer type, in the sense that a pointer of that type can point to an object of any type. But there is no dynamism as that term is usually applied in this sort of context, because values of type void * do not contain any information about the type of object to which they point.
The use, then, is for pointers where the type of the object pointed to does not matter (for a given purpose). In some cases the size of the pointed-to object does matter, however, so that is sometimes provided alongside such pointers. The standard qsort() function is a canonical example. In other cases, such as generic linked lists, it is up to the user to know, somehow, what type of object is pointed to.
As #Vlad already observed, however, casting between void * and other object pointer types is not required in C. Such conversions are performed automatically upon assignment, and in other contexts that use the same rules as assignment.
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.
I have a situation where in the address inside the void pointer to be copied to a another pointer. Doing this without a type cast gives no warnings or errors. The pseudo code looks like
structA A;
void * p = &A;
structA * B = p;// Would like to conform this step
I don't foresee any problems with this.
But since this operation is used over a lot of places, I would like to conform whether it can have any replications. Also is there any compiler dependency?
No, this is fine and 100% standard.
A void * can be converted to and from any other data/object pointer without problems.
Note that data/object restriction: function pointers do not convert to/from void *.
This is the reason why you shouldn't cast the return value of malloc(), which returns a void *.
In C a void * is implicitly compatible with any pointer. That why you don't need to cast when e.g. passing pointers of any type to functions taking void * arguments, or when assigning to pointer (still of any type) from function returning void * (here malloc is a good example).