26

void * is a generic pointer, but what about void **? Is void ** also a generic pointer?

Can we typecast void ** to int **, char ** and so on.

I would be thankful to stack overflow family for any information on this.

filmor
  • 30,840
  • 6
  • 50
  • 48
Adarsh
  • 883
  • 7
  • 18
  • you can do this void **ptr; *((int *)*ptr); – nikhil mehta Aug 21 '14 at 13:31
  • 1
    @nikhilmehta no. But you can do `void *ptr; **(int**)ptr;`. As a rule of thumb, never dereference `void*`, and never cast across more than one level of pointers. – Quentin Aug 21 '14 at 13:32
  • 4
    @Quentin nikhil's usage is fine, if `ptr` actually points at an initialized `void*` object: `int n = 0; void *pn = &n; void **ptr = &pn; int n2 = *((int*) *ptr);` – aschepler Aug 21 '14 at 13:38
  • 2
    It is easy to see that a `void **` is not generic when you remember that it points to a *pointer* (forget about the type of pointer it points to, for a moment). It points to a pointer, and pointers have an implementation defined size and occupy memory and are formatted in a specific way. – ArjunShankar Aug 21 '14 at 13:39
  • 1
    @aschepler oops, indeed. `void*` is definitely a slippery thing. – Quentin Aug 21 '14 at 13:40
  • Just adding on, the standard (both C and C++) explicitly allows pointers of different types to be different sizes: http://stackoverflow.com/questions/916051/are-there-are-any-platforms-where-pointers-to-different-types-have-different-size void* is always sufficiently large to hold all pointer types, but consider this: `int** x = new int*[10]; void** y = (void**)x;`. When you do this, while x==y, x+1!=y+1 if the sizeof(int*)!=sizeof(void*), and *x!=*y – IdeaHat Aug 21 '14 at 13:44
  • Arjun, you mean to say (void **) could be type casted. – Adarsh Aug 21 '14 at 13:45

4 Answers4

28

No. void** is a pointer to void*, and nothing else. Only void* acts like a generic pointer.

Note that actually trying it will probably yield consistent results, but only the above is mandated by the Standard, anything else is Undefined Behaviour and may crash without mercy.

Quentin
  • 62,093
  • 7
  • 131
  • 191
8

void** is a pointer to void*. On top of it being undefined behavior (which while scary, the behavior is often in effect defined by your compiler), it is also a huge problem if you do the reinterpret_cast:

int x = 3;
char c = 2;
int* y = &x;
void* c_v = &c; // perfectly safe and well defined
void** z = reinterpret_cast<void**>(&y); // danger danger will robinson

*z = c_v; // note, no cast on this line
*y = 2; // undefined behavior, probably trashes the stack

Pointers to pointers are very different beasts than pointers. Type changes that are relatively safe on pointers are not safe on pointers to pointers.

Yakk - Adam Nevraumont
  • 262,606
  • 27
  • 330
  • 524
7

Void ** a generic pointer?

void ** is not a generic pointer. Standard says only about void * to be a generic pointer.

Chapter 22: Pointers to Pointers:

One side point about pointers to pointers and memory allocation: although the void * type, as returned by malloc, is a generic pointer, suitable for assigning to or from pointers of any type, the hypothetical type void ** is not a generic pointer to pointer.


Can we typecast void ** to int **, char ** and so on.

No. You should not.

C-FAQ says that:

There is no generic pointer-to-pointer type in C. void * acts as a generic pointer only because conversions (if necessary) are applied automatically when other pointer types are assigned to and from void *'s; these conversions cannot be performed if an attempt is made to indirect upon a void ** value which points at a pointer type other than void *. When you make use of a void ** pointer value (for instance, when you use the * operator to access the void * value to which the void ** points), the compiler has no way of knowing whether that void * value was once converted from some other pointer type. It must assume that it is nothing more than a void *; it cannot perform any implicit conversions.

In other words, any void ** value you play with must be the address of an actual void * value somewhere; casts like (void **)&dp, though they may shut the compiler up, are nonportable (and may not even do what you want; see also question 13.9). If the pointer that the void ** points to is not a void *, and if it has a different size or representation than a void *, then the compiler isn't going to be able to access it correctly.

haccks
  • 104,019
  • 25
  • 176
  • 264
  • 1
    In particular, there are systems where `sizeof(char*) != sizeof(int*)`. (I.e., non-byte-addressable systems.) – Raymond Chen Aug 21 '14 at 14:35
  • 1
    @RaymondChen: do you know such systems sold today? Indeed the 1990 Cray supercomputer had `sizeof(char*) != sizeof(int*)` but I cannot name a processor or computer system sold *today* having this property. – Basile Starynkevitch Aug 21 '14 at 14:56
  • It is not common in general purpose processors, but [according to this SO answer](http://stackoverflow.com/a/3520224/902497) it can happen on DSPs. – Raymond Chen Aug 21 '14 at 19:26
1

C implementations are free to extend the language in such a way as to allow void** to be used as a generic pointer-to-anything type in the presence of suitable casting operators, and in the days before the Standard implementations that could practically do so often did. The Standard does not mandate such treatment because there are some platforms that could not efficiently accommodate such usage. Presumably, the authors judged that requiring that programmers who need to make their code work on such platforms jump through hoops to work around the lack of a "pointer to any data pointer" type would be less harmful than requiring that implementations jump through hoops to accommodate such constructs without regard for whether their customers would use them. Such judgment does not imply that the authors of the Standard intended to require that programmers jump through such hoops even when writing code that would never be called upon to run on such platforms. Clang and gcc can be configured to support such constructs via the -fno-strict-aliasing option.

supercat
  • 77,689
  • 9
  • 166
  • 211