5

I missed a couple classes, and don't really understand the flowing lecture slide's examples about the void pointer.

  1. In the line "no,no,no", why we cannot deference P since P has been assigned a real pointer type q?

  2. In the line " ?? ", is it legal to cast a pointer to a integer? ( I think it can compile because C doesn't check cast, but don't know what kind of result it is going to get

in this example Conversion of integer pointer to integer
he casted *p = 10; a = (int)p; and someone answered that a is going to be a very large value. but in my case,is (int) *p... Is it the same case as the example that I gave above?

  1. In the last line, I am confused about the expression. Is * ((int *)p) actually = p? Thanks!

enter image description here

enter image description here

Community
  • 1
  • 1
overloading
  • 145
  • 9
  • "assigned" and "assigned to" are opposites. It says that to use `p` you must assign its value **to** another variable (e.g. `int *q = p;`) and then use that other variable. (Or cast). – M.M Dec 06 '15 at 22:14

4 Answers4

7

"void*" means "this value is a pointer to something, but I'm not telling you what it points to". Start with this statement, and everything makes sense.

So it should be clear that you can't dereference a void*, because nobody told you what it points to! If you don't know whether it points to an int, a char, or some struct, what do you think should happen if you dereference it?

In C, you can assign a void* to any pointer, for example to an int*. The compiler doesn't know what the void* points to, but when you write r = p; the compiler says "I hope you know what you are doing, I trust you. " (A C++ compiler in the same situation doesn't trust you). If the void* p did indeed point to an int, everything is fine. Otherwise, things are more or less bad.

The ?? one is wrong. You can't dereference *p. Doesn't matter what you do afterwards, *p isn't allowed. And no pointer is cast to an integer. There is an attempt to dereference a pointer, which isn't allowed. The result of the dereference couldn't be anything useful since you don't know what p points to, so you have nothing useful to cast to an int.

Now what happens in * (int *) p: p is a void * - a pointer to something, but you don't know what it points to. (int * )p is a cast: p is converted to an int*. That means the compiler will believe that (int*)p points to an int - that may or may not be true. * (int * ) p dereferences the int*: So in total, you convinced the compiler that p points to an int, and to read the int that p hopefully points to. If p did actually point to an int, it's fine. If p didn't point to an int, you're in trouble.

gnasher729
  • 51,477
  • 5
  • 75
  • 98
3

Void pointers are specifically pointers that do not have a data type associated with them. You have to recast them to a specific type (I.e: int*) to have the ability to access their contents.

To clarify your specific points:

1) While p may have a pointer address, it does not have a specific data type associated to it (The data type is necessary for accessing the contents)

2) The result of this action is probably deterministic on the contents. I wouldn't recommend this as a good practice.

3) This is telling the compiler to treat the void pointer as an integer pointer. Therefore, it "knows" the data type associated with it, and accesses it as an int.

J. Murray
  • 1,460
  • 11
  • 19
  • 2
    yes, but the lecture slide above also says that another way is "being assigned to a read pointer type". In the line " p=q",void pointer p is being assigned to a real pointer type q (q is int*). So I think that p can be dereferenced in the line"no, no,no" – overloading Dec 06 '15 at 22:07
  • @overloading `p` is being assigned the value of `q`; it has nothing to do with the type. After `double d = 5.3; int i; i = d;` do we say `i` has been assigned a `double` type? – user253751 Dec 06 '15 at 22:08
3

In the line "no,no,no", why we cannot deference P since P has been assigned a real pointer type q?

int a =2, *q = a, *r; //line 1
void *p;  //line 2
p = q; // line 3
r = p; // line 4

With line 3 above, you are assigning the pointer q to p. But it doesn't change the type of p - it's still a void pointer. So you can't dereference it. So the following is invalid:

printf("%d\n", *p); // p is a void pointer - dereferencing here is illegal

Alternatively, you can do:

printf("%d\n", *((int*) p)); // p is a void pointer

The above is valid. Because, we convert p to int * before dereferencing it. Consider an example,

void func(void *p)
{
   // what's `p` point to here?
}

int main(void)
{
   int i = 5;
   long x = 10;
   void *p;

   p = &i; // line 1
   p = &x; //line 2

func(p);
}

You can comment out either line1 or line2 but is there anyway in func() to know whether p is pointing to a long data or int data? This is no different to your case.

But the conversion from void * to type * (data pointer) is always necessary before accessing the data its pointing to. Note that it can't be any data pointer though. For example,

int i = 42;
float f = 4.0;

void *p = &f;

printf("%d\n", *((int*))p); // wrong!

This is illegal. p points to a float *. Dereferencing as if it's pointing to a int data is wrong.


In the line " ?? ", is it legal to cast a pointer to a integer?

printf("%d\n", (int) *p);

Since p being a void*, you are not allowed dereference in the first place. The cast after dereferencing doesn't change anything and the dereferencing is illegal.

If you were to cast the pointer itself like:

printf("%d\n", (int)p);

This has implementation-defined behaviour in C. C also provides intptr_t/uintptr_t types for the integer to pointer conversions.

P.P
  • 117,907
  • 20
  • 175
  • 238
  • `(int)p` may cause undefined behaviour if no suitable integer corresponds to that pointer. Some people call this situation "implementation-undefined behaviour", i.e. it's implementation-defined but the implementation may define that it's undefined – M.M Dec 06 '15 at 22:35
  • Yes. C standard allows for it: *An integer may be converted to any pointer type. Except as previously specified, the result is implementation-defined, might not be correctly aligned, might not point to an entity of the referenced type, and might be a trap representation*. So it could possibly be undefined too. – P.P Dec 06 '15 at 22:39
  • @M.M According to this answer, that is not possible: https://stackoverflow.com/questions/30190011/can-an-implementation-specify-undefined-behavior Implementation *defined* behavior cannot be un*defined*. – this Dec 06 '15 at 22:40
  • You quoted "an integer may be converted to any pointer type", however we are talking about converting a pointer to an integer. Read the next paragraph after the one you quoted – M.M Dec 06 '15 at 22:48
  • 1
    ha! Here's the relevant part: *Any pointer type may be converted to an integer type. Except as previously specified, the result is implementation-defined. If the result cannot be represented in the integer type, the behavior is undefined. The result need not be in the range of values of any integer type.* – P.P Dec 06 '15 at 22:54
1

If a pointer p has type void *, then the expression *p has type void, and the void type has no value1; that's why you have to convert the pointer to a "real" pointer type before dereferencing it.

Pointers and integers may be converted to each other, but the values are not guaranteed to be meaningful. However, that's not what the line marked ?? is doing; it's attempting to dereference p and cast the result, but since p is a pointer to void, that's not allowed.

The expression *((int *) p) casts p from pointer to void to pointer to int and the dereferences the result. Since p points to a, this evaluates to the value of a (2).


1. The void type is an incomplete type that cannot be completed.
John Bode
  • 119,563
  • 19
  • 122
  • 198