Is it legal to cast a pointer to an array of ints to an int pointer?
int arr[4];
int (*a)[4] = &arr;
int *p = (int*)a;
C 2018 6.3.2.3 7 says we can convert an int (*)[4] to an int *:
A pointer to an object type may be converted to a pointer to a different object type. If the resulting pointer is not correctly aligned for the referenced type, the behavior is undefined…
The alignment is necessarily correct since an array of int must have the alignment required for an int.
However, the only thing the C standard says about the value resulting from this conversion is:
… when converted back again, the result shall compare equal to the original pointer.
This means that an int * can temporarily hold the value of an int (*)[4]. If we execute:
int arr[4];
int (*x)[4] = &arr;
int *y = (int *) x;
int (*z)[4] = (int (*)[4]) y;
then we know x == z is true because the standard tells us that. But we do not know what y is. Because the standard permits different types of pointers to have different representations (use the bits that represent their values in different ways), it is possible that y has no useful meaning as an int *. The C standard does not say the converted pointer can be used to access objects.
Most C implementations either support this deliberately or as an artifact of how they are designed. However, in terms of what the C standard specifies, no guarantee is given.
If the original pointer's initialized to either NULL or a valid pointer to an int[4], then yes. Pointer casts must not violate alignment requirements lest you get UB. A cast such as what I've described won't violate such requirement ̶a̶n̶d̶ ̶f̶u̶r̶t̶h̶e̶r̶m̶o̶r̶e̶ ̶i̶t̶ ̶w̶i̶l̶l̶ ̶b̶e̶ ̶u̶s̶a̶b̶l̶e̶ ̶f̶o̶r̶ ̶d̶e̶r̶e̶f̶e̶r̶e̶n̶c̶i̶n̶g̶ ̶b̶e̶c̶a̶u̶s̶e̶ ̶i̶f̶ ̶t̶h̶e̶ ̶̶i̶n̶t̶(̶*̶a̶)̶[̶4̶]̶̶ ̶i̶s̶ ̶v̶a̶l̶i̶d̶ ̶a̶n̶d̶ ̶n̶o̶n̶n̶u̶l̶l̶ ̶t̶h̶e̶n̶ ̶t̶h̶e̶r̶e̶ ̶i̶n̶d̶e̶e̶d̶ ̶i̶s̶ ̶a̶n̶ ̶̶i̶n̶t̶̶ ̶a̶t̶ ̶̶(̶i̶n̶t̶*̶)̶a̶̶.
If you feel uneasy about pointer casts (as you should), you can effect the conversion in this case without casting by simply doing *a (will get int[4] which will decay to int*) or a[0] or &a[0][0] or &(*a)[0]. That way, you can also dereference the result while adhering to the letter of the standard.
Related
unsigned int num = 101;
void * p = #
void ** pp = &p;
unsigned int *get_data_1 = NULL;
unsigned int *get_data_2 = NULL;
get_data_1 = *((unsigned int *)pp);
get_data_2 = *((unsigned int **)pp);
Here get_data_1 and get_data_2 what will be the difference?
I have type casted with (unsigned int *) and (unsigned int **).
Both operations invoke Undefined Behavior. The value of type void* pointed by pp is accessed via a l-value expression of incompatible type unsigned int or unsigned int* respectively. This violates strict aliasing rule.
As both operations are UB thus there is no defined difference between those two operations.
The correct accessing should be by dereferencing pp first to obtain value of type void* and use implicit casting from void* to unsigned int*. Finally dereference correctly typed pointer:
unsigned int *get_data_3 = *pp;
return *get_data_3;
TL;DR
Don't do any of this, it is dangerous and incorrect C for a number of reasons. My general advise to beginners is to never use the cast operator at all - there shouldn't be a lot of situations where you actually need to use it.
Generally, C allows wild and dangerous pointer conversions between object pointers that are not compatible, as long as there are no alignment concerns regarding the type pointed-at. (6.3.2.3/7)
However, should you first cast to a non-compatible type and then de-reference the pointer, all manner of undefined behavior might kick in. 6.7.6.1:
For two pointer types to be compatible, both shall be identically qualified and both shall be pointers to compatible types.
Also there are the whole "strict aliasing" concerns regarding "lvalue access" (6.5).
Specifically:
(unsigned int *)pp the pointer conversion is probably ok given that pp points at an aligned address.
*((unsigned int *)pp) invokes undefined behavior since a lvalue of type void* is accessed as an unsigned int and they are not compatible types.
unsigned int *get_data_1 = <unsigned int lvalue> is a constraint violation - invalid C. As per 6.5.16.1. C has never allowed an integer to get assigned to a pointer and vise versa, explicit casts are required.
(unsigned int **)pp similarly the pointer conversion in itself is "probably ok". But again unsigned int** is not compatible with void**. Notably, the special generic rules regarding void* conversions do not apply to void**.
*((unsigned int **)pp) accesses a void* as a unsigned int*. Again this is a strict aliasing violation, because although we may convert to/from void* to any object pointer, they need not have the same internal presentation (though in practice it's very likely). They are not compatible types as per the quoted 6.7.6.1.
unsigned int *get_data_2 = <unsigned int* lvalue> is ok.
I've been reading some articles about void* type pointers and found this requirement from the Standard.
6.2.5.27:
A pointer to void shall have the same representation and alignment requirements as a pointer to a character type.39) Similarly, pointers to qualified or unqualified versions of compatible types shall have the same representation and alignment requirements.
I see that the Standard does not guarantee all pointer types have the same length, so the bottom line here is that a void* pointer has the same length and alignment rules as char*, right?
What I don't get is the footnote 39), which says
The same representation and alignment requirements are meant to imply interchangeability as arguments to functions, return values from functions, and members of unions.
My questions are:
What does it mean by "interchangeability"? Does it say the argument and the return values of a function void* Func(void*) can both be char*?
If so, is it an implicit conversion made by the compiler?
And what is it about the members of unions? I really don't get a grasp of the meaning of this. Can anyone give me a simple example?
In C any data pointer can be passed to a function that expects a void * and a void * can be stored to any pointer type. There is an implicit conversion between void * and other pointer types. But this does not mean that this conversion is harmless. On some architectures where void * and int * have a different representation, converting from int * to void * and then back to int * is specified as producing the same pointer value, but the converse does not hold: converting a void * to int * and back to void * may produce a different value, especially if the void * was not obtained by converting an int *.
Interchangeability means that this implicit conversion does not change the representation of the pointer. the conversion can be operated both ways successfully: converting a character pointer to void * and back produces the same pointer and vice versa.
Here is an example:
#include <assert.h>
#include <stdio.h>
#include <string.h>
int main() {
char *s = "abc";
char *s1;
void *p;
void *p1;
assert(sizeof(p) == sizeof(s));
memcpy(&p, &s, sizeof(p));
p1 = s;
assert(p == p1);
memcpy(&s1, &p1, sizeof(s1));
assert(s == s1);
return 0;
}
Note however that this does not imply that !memcmp(&p1, &s, sizeof(p1)) because pointers could have padding bits. Neither can you violate the strict aliasing rule by casting through a void *:
float f = 1.0; unsigned int i = *(int *)(void *)&f; incorrect.
float f = 1.0; unsigned int i; memcpy(&i, &f, sizeof(i)); correct if sizeof(int) == sizeof(float) but may produce a trap value.
What does it mean by "interchangeability"? Does it say the argument and the return values of a function void* Func(void*) can both be char*?
Yes, that is what it says, but it is non-normative text that conflicts with the normative text of the standard. Let’s discuss question 2 and then come back to this.
If so, is it an implicit conversion made by the compiler?
No, not in the situations intended to be addressed by this note.
If there is a visible declaration of void *Func(void *);, and you execute:
char *p = something;
char *q = Func(p);
then the argument p is converted void * and the returned value is converted to char *. But these conversions occur as part of the normal operations of function calls and assignments; they have nothing to do with the types having the same representation or being interchangeable. For example, if you executed code like the above but with int * instead of char *, the conversions would occur between int * and void * even if they do not have the same representations and are not interchangeable. The argument conversion is made because the compiler knows the parameter type of Func, so it performs the conversion as required by the rules for function calls, and the assignment conversion is made because the compiler knows the type of the destination of the assignment, so it performs the conversion as required by the rules for assignment.
However, suppose we have this code:
char *Func(char *);
char *p = something;
char *q = Func(p);
but Func is in fact defined in its library source code as void *Func(void *);. Then the rule in C 2018 6.2.5 281 applies. In the calling code, the compiler is told the parameter and the return type are char *, so no conversion is performed in either case. When passing the char * argument, the compiler passes exactly the bytes that represent a char *. In the receiving function, the code expects a void *. Since the bytes representing a char * are exactly the same as the bytes representing a void *, with the same meaning in regard to the represented address, this works: The function receives the bytes it expects to receive, with the intended meaning. Similarly, when the function returns the bytes for a void * and the calling code interprets those bytes as a char *, it works because the bytes are the same, with the same meaning.
Getting back to question 1, this example where Func is called using the type char *Func(char *) but is defined using the type void *Func(void *) violates the normative part of the C standard. C 2018 6.5.2.2 6 says:
If the function is defined with a type that includes a prototype, and… the types of the arguments after promotion are not compatible with the types of the parameters, the behavior is undefined.
char * is not compatible with void *, so the behavior is not defined by this rule. However, if the calling code is in one translation unit and the called code is in another translation unit, and no information about the calling code or the called function (notably no type information) is passed between translation units except for linking the name to the function, then it is impossible for the C implementation to distinguish our example code from code in which the function is called using a type compatible with its definition. In particular, the fact that char * has the same representation as void * means that the result of compiling the calling code must be identical whether it uses char *Func(char *) or void *Func(void *) (given the caveat that no type information ais passed between translation units), and it means that the result of compiling the function definition must be identical whether it is defined using char * or void *. In other words, a rule of the C standard says the behavior is not defined, but it is logically impossible in this situation for the compiler to compile the example code differently from the code with defined behavior.
I conjecture that this note in the standard may have been the result of the committee, or at least one or more members of it, wanting to say that, at least in some senses, char * could be used in place of void * and vice-versa, but that the committee did not have the time or motivation or other opportunity to draft formal language for this and make it a normative part of the standard, so it settled for making it a note.
And what is it about the members of unions? I really don't get a grasp of the meaning of this. Can anyone give me a simple example?
Consider this union:
union foo
{
void *v;
char *c;
float *f;
} u;
When we write into one union member, as with u.v = &a;, and read from another union member, as with char *p = u.c;, the bytes in the union are reinterpreted in the new type (C 2018 6.5.2.3 3 and note 99). Since void * and char * have the same representation, this reinterpretation must produce the same value. Thus, we are guaranteed that:
char a;
u.v = &a;
printf("%d\n", u.c == &a);
prints “1”. On the other hand, we are not guaranteed that for this code:
float f;
u.v = &f;
printf("%d\n", u.f == &f);
In this code, when &f is converted to void *, a void * might have a different representation from a float *, so the bytes representing &f may be different from the bytes representing (void *) &f. The latter are the bytes stored in u.v. When those bytes are read as u.f and reinterpreted as a float *, they might represent a different value, so the comparison might not evaluate as true.
Footnote
1 The question cites “6.2.5.27,” but the quoted passage is found in clause 6.2.5, paragraph 28, of the official 2018 C standard. The note cited as note 39 is found as note 49.
A pointer is just an address in the memory. You can think the memory is continuous region of a byte, which is very large (e.g. on a 32 bit process it will be 4 GB but usually the process is not able to use the whole depend on the system).
That mean the value of a pointer is actually an integer represent the zero-based index of a byte in the memory (e.g. pointer with value 0 refer to the first byte in the memory but in really you will not be able to de-reference this address due to it is a null pointer).
When you de-reference a pointer what it does is reading/writing to that address. The size to read/write is depend on the type of pointer. If a pointer is int and its size on that system is 32 bits, which is 4 bytes; it will read/write 4 bytes starting at that address. What alignment means is how the value stored in the memory. Let say if the value stored in memory need to be 16-bytes alignment that means its starting address must be multiply with 16.
What I explain here is just a high-level of the pointer, which should be enough for getting started. In reality it have a lot of things related to it like memory protection, paging, etc.
Take a look at the following program. What I don't understand is why do I have to cast the address of the variable x to char* when it actually would be absolutely useless if you think about it for a second. All I really need is only the address of the variable and all the necessary type information is already in place provided by the declaration statement char* ptr.
#include <stdio.h>
int main(void) {
int x = 0x01020309;
char* ptr = &x; /* The GCC compiler is going to complain here. It will
say the following: "warning: initialization from
incompatible pointer type [enabled by default]". I
need to use the cast operator (char*) to make the
compiler happy. But why? */
/* char* ptr = (char*) &x; */ /* this will make the compiler happy */
printf("%d\n", *ptr); /* Will print 9 on a little-endian machine */
return 0;
}
The C Standard, 6.2.5 Types, paragraph 28 states:
A pointer to void shall have the same representation and
alignment requirements as a pointer to a character type.
Similarly, pointers to qualified or unqualified versions of
compatible types shall have the same representation and
alignment requirements. All pointers to structure types shall have
the same representation and alignment requirements as each other.
All pointers to union types shall have the same
representation and alignment requirements as each other.
Pointers to other types need not have the same representation or alignment requirements.
Since different types of pointers can have differing implementations or constraints, you can't assume it's safe to convert from one type to another.
For example:
char a;
int *p = &a
If the implementation has an alignment restriction on int, but not on char, that would result in a program that could fail to run.
This is because pointers of different types point to blocks of memory of different sizes even if they point to the same location.
&x is of type int* which tells the compiler the number of bytes (depending on sizeof(int)) to read when getting data.
Printing *(&x) will return the original value you entered for x
Now if you just do char* ptr = &x; the compiler assigns the address in &x to your new pointer (it can as they are both pointers) but it warns you that you are changing the size of the block of memory being addressed as a char is only 1 byte. If you cast it you are telling the compiler that this is what you intend.
Printing *(ptr) will return only the first byte of the value of x.
You are correct that it makes no practical difference. The warning is there to inform you that there might be something fishy with that assignment.
C has fairly strong type-checking, so most compilers will issue a warning when the types are not compatible.
You can get rid of the warning by adding an explicit cast (char*), which is you saying:
I know what I'm doing, I want to assign this value to my char* pointer even if the types don't match.
Its just simple as you assign integer type to character. similarly you are trying to assign integer type pointer to character type pointer.
Now why is so because this is how c works, if you increment a character pointer it will give you one byte next address and incrementing integer pointer will give you 2 byte next address.
According to your code, x is of type int. So the pointer that points to x should be of type int *. Compiler gives such error because you use a pointer which is not int *.
So make your pointer either int *, or void * then you don't need cast.
For example, I cast a pointer to an int to a pointer to char:
int originalVar = 1;
char *arr = (char *)&originalVar;
Then I cast it back (maybe I pass arr to another function):
int *pOriginal = (int *)arr;
Does it break the rules? Or any undefined behaviors here?
--
Actually my doubts are about understanding the "effective type" in C standard
Does the object pointed by arr always regard int as its effective type?
(Even if arr is passed to another function?)
That works and is well defined because the alignment of the original pointer will match the int.
Only issue casing a char* to an int* can be alignment requirements. Certain architectures require an int to be aligned on a 4-byte boundary (ie. the last two binary digits of the pointer are 0). A char* generally does not have that limitation.
However, since it started as an int*, and int* -> char* is never an issue, this will not cause any issue.
I have just started learning pointers. I have some questions regarding pointers typecasting. Consider below program.
int main(){
int a = 0xff01;
char *s = &a;
char *t = (int *) &a;
printf("%x",*(int *)s);
printf(" %x",*(int *)t);
return 0;
}
The statement char *s = &a gives
warning: incompatible pointer conversion type.
But noticed that the two printf() statements works fine they give me the right output. The question is
char *t , char *s both are pointers to character type.
Why does 'C' compilers lets me to assign integer variable to char *p ? why dont they raise an error and restrict the programmer?
We have int *ptr to point to integer variables, then why do they still allow programmer to make char *ptr point to integer variable?
// Another sample code
char s = 0x02;
int *ptr = (char *)&s;
printf("%x",*(char *)ptr); // prints the right output
Why does an int *ptr made point to character type? it works. why compiler dont restrict me?
I really think this leads me to confusion. If the pointer types are interchangeable with a typecast then what is the point to have two different pointers char *ptr , int *ptr ?
when we could retrieve values using (int *) or (char *).
All pointers are of same size 4bytes(on 32bite machine). Then one could use void pointer.
Yes people told me, void pointers always needs typecasting when retrieving values from memory. When we know the type of variable we go for that specific pointer which eliminates the use of casting.
int a = 0x04;
int *ptr = &a;
void *p = &a;
printf("%x",*ptr); // does not require typecasting.
printf("%x",*(int *)p); // requires typecasting.
Yes, I have read that back in old days char *ptrs played role of void pointers. Is this one good reason? why still compilers support typecasting between pointers? Any help is greatly appreciated.
Compiling with GCC 4.9.1 on Mac OS X 10.9.5, using this mildly modified version of your code (different definition of main() so it compiles with my preferred compiler options, and included <stdio.h> which I assume was omitted for brevity in the question — nothing critical) in file ptr.c:
#include <stdio.h>
int main(void)
{
int a = 0xff01;
char *s = &a;
char *t = (int *) &a;
printf("%x",*(int *)s);
printf(" %x",*(int *)t);
return 0;
}
I get the compilation errors:
$ gcc -O3 -g -std=c11 -Wall -Wextra -Wmissing-prototypes -Wstrict-prototypes \
-Wold-style-definition -Werror ptr.c -o ptr
ptr.c: In function ‘main’:
ptr.c:6:15: error: initialization from incompatible pointer type [-Werror]
char *s = &a;
^
ptr.c:7:14: error: initialization from incompatible pointer type [-Werror]
char *t = (int *) &a;
^
cc1: all warnings being treated as errors
$
So, both assignments are the source of a warning; my compilation options turn that into an error.
All pointers other than void * are typed; they point to an object of a particular type. Void pointers don't point to any type of object and must be cast to a type before they can be dereferenced.
In particular, char * and int * point to different types of data, and even when they hold the same address, they are not the same pointer. Under normal circumstances (most systems, most compilers — but there are probably exceptions if you work hard enough, but you're unlikely to be running into one of them)…as I was saying, under normal circumstances, the types char * and int * are not compatible because they point to different types.
Given:
int data = 0xFF01;
int *ip = &data;
char *cp = (char *)&data;
the code would compile without complaint. The int data line is clearly unexceptional (unless you happen to have 16-bit int types — but I will assume 32-bit systems). The int *ip line assigns the address of data to ip; that is assigning a pointer to int to a pointer to int, so no cast is necessary.
The char *cp line forces the compiler's hand to treat the address of data as a char pointer. On most modern systems, the value in cp is the same as the value in ip. On the system I learned C on (ICL Perq), the value of a char * address to a memory location was different from the 'anything else pointer' address to the same memory location. The machine was word-oriented, and byte-aligned addresses had extra bits set in the high end of the address. (This was in the days when the expansion of memory from 1 MiB to 2 MiB made a vast improvement because 750 KiB were used by the O/S, so we actually got about 5 times as much memory after as before for programs to use! Gigabytes and gibibytes were both fantasies, whether for disk or memory.)
Your code is:
int a = 0xff01;
char *s = &a;
char *t = (int *) &a;
Both the assignments have an int * on the RHS. The cast in the second line is superfluous; the type of &a is int * both before and after the cast. Assigning an int * to a char * is a warnable offense — hence the compiler warned. The types are different. Had you written char *t = (char *)&a;, then you would have gotten no warning from the compiler.
The printing code works because you take the char * values that were assigned to s and t and convert them back to the original int * before dereferencing them. This will usually work; the standard guarantees it for conversions to void * (instead of char *), but in practice it will normally work for anything * where anything is an object type, not a function type. (You are not guaranteed to be able to convert function pointers to data pointers and back again.)
The statement char *s = &a gives
warning: incompatible pointer conversion type.
In this case, the warning indicates a constraint violation: A compiler must complain and may refuse to compile. For initialization (btw, a declaration is not a statement), the same conversion rules as for assignment apply, and there is no implicit conversion from int * to char * (or the other way round). That is, an explicit cast is required:
char *s = (char *)&a;
Why do C compilers let me assign an integer variable to char *p? Why don’t they raise an error and restrict the programmer?
Well, you’ve got a warning. At the very least, a warning means you must understand why it is there before you ignore it. And as said above, in this case a compiler may refuse to compile.*)
We have int *ptr to point to integer variables, then why do they still allow programmer to make char *ptr point to integer variable?
Pointers to a character type are special, they are allowed to point to objects of every type. That you’re allowed to do so, doesn’t mean it’s a good idea, the cast is required to keep you from doing such a conversion accidently. For pointer-to-pointer conversions in general, see below.
int *ptr = (char *)&s;
Here, ptr is of type int *, and is initialized with a value of type char *. This is, again, a constraint violation.
printf("%x",*(char *)ptr); // prints the right output
If a conversion from a pointer to another is valid, the conversion back also is and always yields the original value.
If the pointer types are interchangeable with a typecast then what is the point to have two different pointers char *ptr, int *ptr?
Types exist to save you from errors. Casts exist to give you a way to tell the compiler that you know what you’re doing.
All pointers are of same size 4bytes(on 32bite machine). Then one could use void pointer.
That’s true for many architectures, but quite not for all the C standard addresses. Having only void pointers would be pretty useless, as you cannot really do anything with them: no arithmetic, no dereferencing.
Yes, I have read that back in old days char *ptrs played role of void pointers. Is this one good reason?
Perhaps a reason. (If a good one, is another question…)
When pointer-to-pointer conversions are allowed:
C11 (N1570) 6.3.2.3 p7
A pointer to an object type may be converted to a pointer to a different object type. If the resulting pointer is not correctly aligned×) for the referenced type, the behavior is undefined. Otherwise, when converted back again, the result shall compare equal to the original pointer. When a pointer to an object is converted to a pointer to a character type, the result points to the lowest addressed byte of the object. Successive increments of the result, up to the size of the object, yield pointers to the remaining bytes of the object.
×) In general, the concept “correctly aligned” is transitive: if a pointer to type A is correctly aligned for a pointer to type B, which in turn is correctly aligned for a pointer to type C, then a pointer to type A is correctly aligned for a pointer to type C.
Pointers to character types and pointers to void, as mentioned above, are always correctly aligned (and so are int8_t and uint8_t if they exist). There are platforms, on which a conversion from an arbitrary char pointer to an int pointer may violate alignment restrictions and cause a crash if executed.
If a converted pointer satisfies alignment requirements, this does not imply that it’s allowed to dereference that pointer, the only guarantee is that it’s allowed to convert it back to what it originally pointed to. For more information, look for strict-aliasing; in short, this means you’re not allowed to access an object with an expression of the wrong type, the only exception being the character types.
*) I don’t know the reasons in your particular case, but as an example, where it’s useful to give implementations such latitude in how to treat ill-formed programmes, see for example object-pointer-to-function-pointer conversions: They are a constraint violation (so they require a diagnostic message from the compiler) but are valid on POSIX systems (which guarantess well-defined semantics for such conversions). If the C standard required a conforming implementation to abort compilation, POSIX had to contradict ISO C (cf. POSIX dlsym for an example why these conversions can be useful), which it explicitly doesn’t intend to.
Pointers are not having any types, types described with pointer in program actually means that to which kind of data pointer is pointing. Pointers will be of same size.
When you write,
char *ptr;
it means that is is pointer to character type data and when dereferenced, it will fetch one bytes data from memory
Similarly,
double *ptr;
is pointer to double type data. So when you dereference, they will fetch 8 bytes starting from the location pointed by pointer.
Now remember that all the pointer are of 4 bytes on 32 bit machines irrespective of the type of data to which it is pointing. So if you store integer variable's address to a pointer which is pointing to character, it is completely legal and if you dereference it, it will get only one byte from memory. That is lowest byte of integer on little endian pc and highest byte of integer on big endian pc.
Now you are type casting your pointer to int type explicitly. So while dereferencing it will get while integer and print it. There is nothing wrong with this and this is how pointers work in c.
In your second example you are doing the same. Assigning address of character type variable to pointer which is pointing to integer. Again you are type casting pointer to character type so by dereference it will get only one byte from that location which is your character.
And frankly speaking, i dont know any practical usage of void pointer but as far as i know, void pointers are used when many type of data is to be dereferenced using a single pointer.
Consider that you want to store an integer variable's address to pointer. So you will declare pointer of integer type. Now later in program there is a need to store a double variable's address to pointer. So instead of declaring a new pointer you store its address in int type pointer then if you dereference using it, there will be a big problem and result in logical error which may get unnoticed by you if you have forgot to type cast it to double type. This is not case with void pointer. If you use void pointer, you have to compulsarily type cast it to particular type inorder to fetch data from memory. Otherwise compiler will show error. So in such cases using void pointer reminds you that you have to type cast it to proper type every time otherwise compiler will show you error. But no error will be shown in previous case