3
#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.

Jens Gustedt
  • 76,821
  • 6
  • 102
  • 177
pupu007
  • 149
  • 1
  • 10

3 Answers3

8

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.

Community
  • 1
  • 1
jamesdlin
  • 81,374
  • 13
  • 159
  • 204
-1

You need to typecast the pointer in swap call. Change it to swap ( ( void * )s, 0, 1 );

unxnut
  • 8,509
  • 3
  • 27
  • 41
  • @Jens Gustedt: Is ( void * )s changing from void * to a different type? – unxnut May 15 '13 at 12:04
  • `( void * )s` by itself not, but since the first parameter of `swap` is `void**` an implicit conversion to that is taking place immediately after the explicit cast and before calling the function. – Jens Gustedt May 15 '13 at 12:12
  • @unxnut: You're essentially casting `char**` => `void*` => `void**`. `char**` and `void**` are not the same type. – jamesdlin May 15 '13 at 15:33
  • No, the code is just casting char * => void * and swapping the void * pointers, effectively swapping the char * pointers. It does not dereference the void * pointers in any way. – unxnut May 15 '13 at 15:40
  • @unxnut: No, `swap` takes a `void**`. And while it does not dereference a `void*` type, it does dereference `void**` (via `v[i]` and `v[j]`) and assumes that `sizeof (void*) == sizeof (char*)`. – jamesdlin May 15 '13 at 16:08
-1

To avoid the warning call the function as follows,

swap((void *) s, 0, 1);

It is always safe to cast any pointer as a void pointer.

Deepu
  • 7,592
  • 4
  • 25
  • 47
  • 1
    You're actually casting a `char**` to a `void*` which then is being implicitly cast to a `void**`. Casting a `T**` to a `void**` is not necessarily safe. – jamesdlin May 15 '13 at 05:17
  • This answer is wrong. Converting **to** `void*` is always safe, but the implicit conversion from `void*` to a different type than the original isn't. – Jens Gustedt May 15 '13 at 07:35
  • @JensGustedt why? some computers make that different representations for pointers to different types.So void *[] may make a worry pointing to char *[] – pupu007 May 15 '13 at 12:27
  • @pupu007 a function parameter of `void*[]` is equivalent to a `void**`. I don't understand your use of "worry". – Jens Gustedt May 15 '13 at 12:32