Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

What does this mean: a pointer to void will never be equal to another pointer?

One of my friends pointed out from "Understanding and Using C Pointers - Richard Reese, O'Reilly publications" the second bullet point and I wasn't able to explain the first sentence from it. What am I missing?

Pointer to void

A pointer to void is a general-purpose pointer used to hold references to any data type. An example of a pointer to void is shown below:

void *pv; 

It has two interesting properties:

  • A pointer to void will have the same representation and memory alignment as a pointer to char.
  • A pointer to void will never be equal to another pointer. However, two void pointers assigned a NULL value will be equal.

This is my code, not from the book and all pointers are having the same value and are equal.

#include <stdio.h>  int main() {   int a = 10;    int *p = &a;    void *p1 = (void*)&a;   void *p2 = (void*)&a;    printf("%p %p\n",p1,p2);   printf("%p\n",p);      if(p == p1)      printf("Equal\n");   if(p1 == p2)      printf("Equal\n");   } 

Output:

 0x7ffe1fbecfec 0x7ffe1fbecfec  0x7ffe1fbecfec  Equal  Equal 
like image 343
InQusitive Avatar asked Aug 01 '21 13:08

InQusitive


People also ask

What does a pointer to void mean?

A pointer in a program that isn't associated with a data type is known as a void pointer in C. The void pointer points to the data location. The void pointer in C is a pointer that is not associated with any data types. It points to some data location in the storage.

What does void * mean in C?

void* is a "pointer to anything". void ** is another level of indirection - "pointer to pointer to anything". Basically, you pass that in when you want to allow the function to return a pointer of any type.

Can a void pointer point to a pointer?

A void pointer is a pointer that can point to any type of object, but does not know what type of object it points to. A void pointer must be explicitly cast into another type of pointer to perform indirection. A null pointer is a pointer that does not point to an address.

What does a pointer to void mean?

A pointer to void means a generic pointer that can point to any data type. We can assign the address of any data type to the void pointer, and a void pointer can be assigned to any type of the pointer without performing any explicit typecasting.

Is it illegal to dereference a void pointer in C?

Hence, dereferencing a void pointer is illegal in C. But, a pointer will become useless if you cannot dereference it back. To dereference a void pointer you must typecast it to a valid pointer type. What is a void pointer can you dereference a void pointer without knowing its type? 4 Answers.

Can a pointer point to any type of variable?

Till now, we have studied that the address assigned to a pointer should be of the same type as specified in the pointer declaration. For example, if we declare the int pointer, then this int pointer cannot point to the float variable or some other type of variable, i.e., it can point to only int type variable.

Is it possible to do arithmetic arithmetic with a void pointer?

2) The C standard doesn’t allow pointer arithmetic with void pointers. However, in GNU C it is allowed by considering the size of void is 1. For example the following program compiles and runs fine in gcc.


2 Answers

TL/DR: the book is wrong.

What am I missing?

Nothing, as far as I can see. Even the erratum version presented in comments ...

A pointer to void will never be equal to another pointer to void.

... simply is not supported by the C language specification. To the extent that the author is relying on the language specification, the relevant text would be paragraph 6.5.9/6:

Two pointers compare equal if and only if both are null pointers, both are pointers to the same object (including a pointer to an object and a subobject at its beginning) or function, both are pointers to one past the last element of the same array object, or one is a pointer to one past the end of one array object and the other is a pointer to the start of a different array object that happens to immediately follow the first array object in the address space.

void is an object type, albeit an "incomplete" one. Pointers to void that are valid and non-null are pointers to objects, and they compare equal to each other under the conditions expressed by the specification. The usual way that such pointers are obtained is by converting an object pointer of a different (pointer) type to void *. The result of such a conversion still points to the same object that the original pointer did.

My best guess is that the book misinterprets the spec to indicate that pointers to void should not be interpreted as pointers to objects. Although there are special cases that apply only to pointers to void, that does not imply that general provisions applying to object pointers do not also apply to void pointers.

like image 150
John Bollinger Avatar answered Sep 23 '22 13:09

John Bollinger


C 2018 6.5.9 6 says:

Two pointers compare equal if and only if both are null pointers, both are pointers to the same object (including a pointer to an object and a subobject at its beginning) or function, both are pointers to one past the last element of the same array object, or one is a pointer to one past the end of one array object and the other is a pointer to the start of a different array object that happens to immediately follow the first array object in the address space.

So, suppose we have:

int a; void *p0 = &a; void *p1 = &a; 

Then, if p0 and p1 “point to the same object”, p0 == p1 must evaluate as true. However, one might interpret the standard to mean that a void * does not point to anything while it is a void *; it just holds the information necessary to convert it back to its original type. But we can test this interpretation.

Consider the specification that two pointers compare equal if they point to an object and a subobject at its beginning. That means that given int a[1];, &a == &a[0] should evaluate as true. However, we cannot properly use &a == &a[0], because the constraints for == for pointers require the operands point to compatible types or that one or both is a void * (with qualifiers like const allowed). But a and a[0] neither have compatible types nor are void.

The only way for a fully defined situation to arise in which we are comparing pointers to this object and its subobject is for at least one of the pointers to have been converted either to void * or to a pointer to a character type (because these are given special treatment in conversions). We could interpret the standard to mean only the latter, but I judge the more reasonable interpretation to be that void * is included. The intent is that (void *) &a == (void *) &a[0] is to be interpreted as a comparison of a pointer to the object a to a pointer to the object a[0] even though those pointers are in the form void *. Thus, these two void * should compare as equal.

like image 35
Eric Postpischil Avatar answered Sep 20 '22 13:09

Eric Postpischil