Why do we have to cast a void pointer to int or something else before printing the value in the memory whose address is in the pointer?

风流意气都作罢 提交于 2019-12-10 16:26:30

问题


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

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!