Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Is casting to pointers to pointers to void always safe?

Tags:

c

pointers

void

#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;
}

Output:

one, two

two, one

Warning: 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.

like image 596
pupu007 Avatar asked Oct 17 '25 19:10

pupu007


1 Answers

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;
        item1++;
        item2++;
    }
}

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

like image 166
jamesdlin Avatar answered Oct 20 '25 09:10

jamesdlin



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!