pupu007 pupu007 - 3 months ago 37
C Question

Is casting to pointers to pointers to void always safe?

#include <stdio.h>

void swap(void *v[], int i, int j)
void *tmp;

tmp = v[i];
v[i] = v[j];
v[j] = tmp;

int main(void)
char *s[] = {"one", "two"};
printf("%s, %s\n", s[0], s[1]);
swap(s, 0, 1);
printf("%s, %s\n", s[0], s[1]);
return 0;


one, two

two, one

no compatible pointer casting, need void**, but char

I used this program to simulate the swap function in K&R, to demonstrate the use of the function pointer, and my question is whether the cast of the
void pointer
is always safe, or if there is any way to replace it.


No, it is not necessarily safe to pass a char** where a void** (which is what a void*[] function parameter actually is) is expected. The fact that the compiler makes you perform an explicit cast is a hint about that.

In practice, it is likely to be fine. Strictly speaking, however, you usually have no guarantee that sizeof (T*) == sizeof (U*) for distinct types T and U. (For example, you could imagine a hypothetical system where sizeof (int*) < sizeof (char*) because pointers-to-int are aligned and therefore don't need to store the least significant bits.) Consequently, your swap function might index into the v array using the wrong offsets.

Also see Q4.9 from the comp.lang.c FAQ: Can I give the formal parameter type void **, and do something like this?

To call swap safely, you should do something like:

void* temp[] = { &s[0], &s[1] };
swap(temp, 0, 1);

although that would swap the elements of temp, not of s.

If you're authoring swap, in general you should make such a function take a void* argument (instead of a void** one) and a size_t argument that specifies the size of each element. Your function then could cast the void* to char* safely and swap individual bytes:

void swap(void* p, size_t elementSize, size_t i, size_t j)
    char* item1 = p;
    char* item2 = p;

    item1 += i * elementSize;
    item2 += j * elementSize;

    while (elementSize-- > 0) {
        char temp = *item1;
        *item1 = *item2;
        *item2 = temp;

Edit: Also see this StackOverflow answer to a similar question.