I've seen a lot of the following in older C code:
type_t *x = (type_t *) malloc(...);
What's the point of casting the pointer returned from malloc() since it's void *? Is it because older C compilers didn't support void pointers and malloc() used to return char * instead?
Your own explanation is the right one. Pre-ANSI C ('K&R' C) did not have a void * type with implicit conversion. char * doubled as a pseudo void * type, but you needed the explicit conversion of a type cast.
In modern C the casting is frowned upon because it can suppress compiler warnings for a missing prototype of malloc. In C++, the casting is needed (but there you should be using new instead of malloc most of the time).
Update
My comments below that try to explain why the cast is required were a bit unclear, I'll try to explain it better here. You might think that even when malloc returns char *, the cast is not needed because it is similar to:
int *a;
char *b = a;
But in this example a cast is also needed. The second line is a constraint violation for the simple assignment operator (C99 6.5.1.6.1). Both pointer operands need to be of compatible type. When you change this to:
int *a;
char *b = (char *) a;
the constraint violation disappears (both operands now have type char *) and the result is well-defined (for converting to a char pointer). In the 'reverse situation':
char *c;
int *d = (int *) c;
the same argument hold for the cast, but when int * has stricter alignment requirements than char *, the result is implementation defined.
Conclusion: In the pre-ANSI days the type cast was necessary because malloc returned char * and not casting results is a constraint violation for the '=' operator.
The problem here is not compatibility with any dialect of C. The problem is C++. In C++, a void pointer cannot be automatically converted to any other pointer type. So, without an explicit cast, this code would not compile with a C++ compiler.
I'm not aware that malloc ever returned a char*.
But implicit casting from void* to type_t* (or any other type) hasn't always been allowed.
Hence, the need to explicitly cast to the proper type.
What's the point of casting the pointer returned from malloc() since it's void *?
Quite the contrary. You need to cast a void pointer to an actual type before you can use it, because a void * signifies nothing about the data stored at that location.
Related
I ran into a weird code snippet while following an image processing guide. The language is C. What is the purpose of taking an address, casting the pointer, then dereferencing it? I am new to C, so I am unsure if this is a common practice and its purpose.
unsigned char header[];
// not sure why we are dereferencing the array then getting its address and casting it into an int pointer then dereferencing that.
int width = *(int *)&header[18];
int height = *(int *)&header[22];
int bitDepth = *(int *)&header[28];
// why not this?
int width = (int) header[18];
int height = (int) header[22];
int bitDepth = (int) header[28];
I am unsure if this is a common practice and its purpose.
Code like this is a problem.
Aliasing
The behavior of this code is not defined by the C standard because it violates the aliasing rules in C 2018 6.5 7. (Other) answers tell you what the author of the code may have intended to do, but code like this should not be used without a guarantee from the compiler that it supports this aliasing. You should avoid writing code like this.
#Eric Postpischil
Alignment
(int *)&header[18] and others risks alignment failure and undefined behavior (UB). Don't do it.
Endian
Result is endian dependent. Proceed with caution.
Rather than poorly code, use memcpy() and let the compiler emit efficient code.
// int width = *(int *)&header[18];
int width;
memcpy(&width, &header[18], sizeof width);
It seems the type of the pointer header is not int *. Maybe it has the type void * or char * or unsigned char *.
So to get an integer you need to cast the pointer to the type int * and then to dereference it to get the value pointed to by the pointer.
The type that & returns is a pointer type. In this case, it is a pointer to the 18th element of the array (17th if you start from the zeroth element).
(int *) &header[18];
(int *) is then casting the pointer type returned by & to an int pointer, or int *.
*(int *) &header[18];
The * then dereferences that int pointer, or int *, to initialize width.
Now, to answer your question:
Why the cast?
Because the type of the pointer header might not be an int *, hence the cast.
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 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);
Knowing more C++ than C I wondered if someone could explain the reason why malloc() always returns a pointer of type void, rather than malloc having been implemented with some mechanism which allows it to return a pointer of the type the user passed in? It just seems a little "hacky" constantly explicitly casting the returned void pointer to the type you want.
Well, in C you don't have to do the cast, so your point is moot. That is, these two statements are 100% equivalent:
char *x = malloc(100);
char *y = (char *)malloc(100);
Conversions to and from void * are implicit in C. So, to address your question, the very reason malloc returns void * is so that you don't have to cast.
Besides that, in C there's no way to pass type information around, so doing something like:
char *x = malloc(100, char);
is not possible.
If you're in C++, the cast is necessary, but you shouldn't be using malloc anyway - that's what new is for, and it does handle the type information correctly.
It's not hacky at all, from C standard ISO/IEC 9899 2011, section 6.2.2.3:
A pointer to void may be converted to or from a pointer to any object type. A pointer to any object type may be converted to a pointer to void and back again; the result shall compare equal to the original pointer.
So a pointer to void* is a valid pointer to whatever type you want without the need of explicit casting.
In addition to this you can't dynamically pass a type to a function to let so that it will return the correct type, you can pass just the size itself (so malloc would be able to allocate size_t count * size_t size but not return the correctly type in any case).
C has no mechanism for "passing a type" at all. Also, in C, conversion from void* to a pointer of any other type is automatic (no cast is needed) so malloc works naturally in C. It's only in C++ where malloc requires casts to work.
There are two reasons, first, malloc doesn't know why you need memory. So it just return number of bytes asked to return. Secondly you cannot de-reference void * easily so it can help you to avoid accidents.
int *p;
p = (int *)malloc(sizeof(int)*10);
I am studying C Language I need some explanation about a code segments,
int *p;
p = (int *) malloc(sizeof(int));
What does the (int *) means and whats really happening when you execute the above Code?
(int *) is a so called cast operator. It is used to convert the value on the right side of the operator to the type enclosed in parenthesis.
Here, it is used to convert the void * pointer returned by malloc() to an int *, i.e. a pointer to an integer.
This is a very bad usage, and you should not do it.
malloc has return type void*, which reads as pointer-to-void which means pointer-to-something.
p has type int*, so pointer-to-int. In order to assign the result of malloc into p, you need to convert int* into void* somehow.
If you write:
int* p = malloc(...)
the conversion happens automatically ("implicit conversion").
If you, for some reason, decide to write:
int* p = (int*) malloc(...)
the result is the same, but the conversion is explicit (i.e. a "cast").
Here's the documentation on malloc.
You're allocating a block of memory the size of an int (this value may change depending on the system/compiler combo).
The (int *) casts the right hand side as an int *, which isn't necessary in C, you just need the malloc.
int *p; // pointer to an integer
p = (int *) malloc(sizeof(int)); // assignment of enough memory for an integer
The (int *) part is called typecasting, you're telling the compiler:
"I know malloc() gives me a void *, but I'm going to assign it to something else".
There are useful reasons to typecast, but it can be dangerous too. In this case since malloc() returns a void * you don't need to typecast because it's automatically and safely converted to other pointer types.
Try this link man malloc
In C, there is no need of typecasting in mallocso write directly
p = malloc(sizeof(int));
FYI , this (int *) is nothing but the typecast. Since many functions return void*
so it needs to typecast in the respective type for further manipulations with pointers.
In case of malloc it's implicitely taken care of
(type) is called type cast operator in C.
suppose for example,
int a;
float b = 11.4;
You want to put the integral value of bin a. Use type casting
a = (int)b
Unwind already gave you the answer, but I want to expand on it a bit.
In C, some types are not compatible; you can't directly assign a value of type T to a variable of type Q; for example, you can't assign a pointer to int to a variable that's type pointer to double:
double *q;
int *p;
...
q = p; // will cause a diagnostic to be issued
If you really need to make that assignment, though, you can use a cast expression, which converts the value to the target type:
q = (double *) p;
This tells the compiler to convert the value of p to pointer to double and assign the result to q.
In the original, K&R version of C, malloc returned char *, so if you wanted to assign the result of malloc to a pointer of a different type, you had to apply the cast:
int *p = (int *) malloc(SIZE);
That changed in 1989, when the first C standard was introduced. That version introduced a void * type to act as a "generic" pointer type. Values of type void * can be assigned to other pointer types directly, without need of a cast. So, as of C89 and later, you can simply write
int *p = malloc(SIZE);
This was not only cleaner, it was also safer; if you forgot to include stdlib.h or otherwise didn't have a declaration for malloc in scope, the compiler would assume that malloc returned an int value and generate code accordingly. Since an int value can't be directly assigned to a pointer type, you would get a diagnostic. If you added the cast, however, that warning would be suppressed, and you would potentially have issues at runtime.
The 1999 standard got rid of the implicit int assumption, so that's no longer a real danger, but it's still better style to leave the cast off of a malloc call.