问题
I wonder why is it necessary to cast a void
pointer to an int *
or char *
before printing the contents of the address in memory, even though we tell the printf()
function how to interpret the data in memory?
Let's say that we have the following code:
int main (void)
{
void* c = malloc(4);
printf("%d",*c);
return 0;
}
Why it is not possible to do this?
So to be clear my question is what is the reason for this being not possible?
EDIT: After all the answers and research I am still not convinced exactly where the fatal error in the compilation is. The main reason I am confused is that my compiler (gcc) only gives a WARNING when telling about "dereferencing a void pointer". Is this the actual error? From what I know the program should still compile even with warnings.
EDIT2 I am still confused about the reasons for which we have an ERROR and a WARNING that appear to be completely separate but are generated by the same piece of code:
pointer.c:7:13: warning: dereferencing 'void *' pointer
printf("%d",*p);
^~
pointer.c:7:13: error: invalid use of void expression
printf("%d",*p);
Some users say that the error appears only when we try to use the result of the derefenciation and that the WARNING is when we actually alocate memory for the VOID pointer.
This is clearly NOT the case since if we remove the printf line we do indeed get only a warning but a COMPLETELY UNRELATED ONE.
pointer.c:6:8: warning: unused variable 'p' [-Wunused-variable]
void * p=malloc(4);
回答1:
The problem is not the interpretation of printf()
, it's with the dereference.
In the case of a statement like
printf("%d",*c);
you are attempting to dereference a void *
. Now, void
is a forever-incomplete type. You cannot dereference a pointer to "something incomplete" and get something meaningful as a result.
Quoting C11
, chapter §6.2.5 , P19
The void type comprises an empty set of values; it is an incomplete object type that cannot be completed.
To put it in other words (though a bit of my own), C is a strongly typed language and for each defined type, the compiler knows (or, must know) how many bytes (size) from memory it needs to read / operate on. For a void
type, the compiler is clueless.
For the very same reason, pointer arithmetic is also not allowed on void *
s. gcc has an extension which treats a void*
the same as char *
, but that's an extension, not standard.
EDIT:
My compiler produces an error for the statement, check online.
回答2:
*c
dereferences the pointer, which is of type void
(an incomplete type). You cannot dereference void
, since the compiler doesn't know the type (thus its size). As a result, dereferencing a void pointer invokes Undefined Behavior.
In other words, it's not reasonable to dereference a void pointer. Imagine you are the compiler, how would you interpter the memory that the pointers is pointing to (since it can be anything)? Casting a void*
to the proper type will do the trick (provide the nessecairy information to the compiler).
Why does the compiler only gives a warning and not an error?
It does, notice that it will generate a warning and a companioned error:
main.c:8:14: warning: dereferencing 'void *' pointer
printf("%d",*c);
^~
main.c:8:14: error: invalid use of void expression
printf("%d",*c);
^~~~~~
(gcc) gives a WARNING when telling about "dereferencing a void pointer". Is this the actual error?
No.
But attempt to use the result of this derefencization and you are in bad luck.
I mean that:
void* c = malloc(4);
*c;
will not cause an error (but only a warning):
main.c:6:2: warning: dereferencing 'void *' pointer
*c;
^~
However if you attempt to use the result of *c
, an error will be generated.
Read more about this in Towards understanding void pointers.
回答3:
Since c
is a void pointer
it could be anything. To dereference the compiler needs to know the type, including the size.
Without the malloc
and void *
, consider what happens here:
int main()
{
int i = 555555;
char * c = (char *)&i;
printf("%c\n", *c);
short * s = (short *)&i;
printf("%d\n", *s);
}
You get very different things printed. The same is going on with the void *
- what is it supposed to be?
You have told printf
to expect a number, but that is a separate operation to dereferncing the void *
in the first place.
回答4:
The c
pointer has been declared void*
. Before accessing/dereferencing void
pointer you need to must type cast,so that it points to relevant type which you are expecting in this pointer.
回答5:
To sum up, as stated by previous answers, void
is an incomplete type in all C standards & therefore you will definitly get an error whenever you try to dereference it. However, GNU C treats void with size of 1 (char) & therefore it only shows a warning but GCC carries on the compilation according to the GNU extension.
If you want GCC to strictly follow the standard you have to add -std=c11
flag (perhaps with -pedantic
).
回答6:
printf
doesn't take pointers to things to print, mostly so that it can accept the result of expressions:
printf("%d",4*my_function()); // value has no user-visible address
As such, the compiler must know the type in order to fetch the value and give that to printf
. (You need the format string too because the language offers printf
's implementation no way of discovering what type of object you gave it.)
来源:https://stackoverflow.com/questions/46234746/why-do-we-have-to-cast-a-void-pointer-to-int-or-something-else-before-printing-t