Re: void pointer arithmetic

From: nospam (h.b.furuseth(nospam)_at_usit.uio(nospam).no)
Date: 11/16/03


Date: 16 Nov 2003 20:02:31 +0100

Alex Fraser wrote:

> From searching Google Groups, I understand that void pointer
> arithmetic is a constraint violation, which is understandable.

Yup.

> However, generic functions like qsort() and bsearch() must in essence
> do exactly this,

No, what these functions do to compare the objects depends on the
original data type of the objects and their semantics. See below.

> In a few posts I read, it was suggested to avoid void pointer
> arithmetic by casting to a char pointer, and performing arithmetic on
> that (in multiples of sizeof(original_type)).

You could, but it's usually cleaner to just cast to pointers the
original type and let the compiler do the sizeof for you.

As for doing pointer arithmetic on the results: If all the pointers
point into the same array, and you really want to sort the pointers by
their index into that array, yes, then you can do that. However,
usually you'll want to do something quite else, e.g.:

static int str_qcmp(const void *a, const void *b)
{
    char *const *ap = a;
    char *const *bp = b;
    return strcmp(*ap, *bp);
}
...
   char *arr[] = { "foo", "bar", "baz" };
   qsort(arr, sizeof(arr)/sizeof(*arr), sizeof(*arr), str_qcmp);
   /* arr = { "bar", "baz", "foo" } */

> I am quite sure this would work on many implementations (where the
> casts are no-ops),

Never mind that. If casts are not no-ops, the casts will modify the
representations of the pointer as appropriate. Unless you make
the mistake of telling the compiler that some data has another type
than it really has, for example by casting the _function pointer_
to another type. For example, I've seen programs that did this:

   static int foo_qcmp(struct foo *a, struct foo *b);
   ...
   qsort(..., (int (*)(const void*, const void*)) foo_qcmp);

Now qsort will pass void pointers to foo_qcmp, but foo_qcmp thinks it is
receives struct foo pointers, so it doesn't convert them from void* to
struct foo*. That fails if void* and struct foo* have different
representations or are passed in different ways to functions.

> Thus the pointer is cast through the sequence
> original_type* -> void* -> char* -> void* -> original_type*.

The standard allows this, because char* and void* have the same
representation and alignment requirements. However,
original_type* -> void* -> original_type* is quite enough.

-- 
Hallvard


Relevant Pages

  • Re: regarding free function in c library
    ... type void* and when we invoke them with pointers to any type, ... No, C does not support "implicit casts", no such thing exists in the ...
    (comp.lang.c)
  • Re: sizeof(ptr) = ?
    ... A void * has the same representation as a char *. ... Char pointers which require additional data ... iff the default offset is 0. ...
    (comp.lang.c)
  • Re: Malloc code
    ... int xxx; ... As for not using the void pointer, I will have to do some further testing ... I just needed some insight on passing arrays of pointers. ... struct MCB *r1; ...
    (microsoft.public.vc.language)
  • Re: polymorphic design approach
    ... > polymorphism. ... * 'Device' pointers are stored so as to allow polymorphic ... virtual void handleMessage ...
    (alt.comp.lang.learn.c-cpp)
  • Re: Realloc and pointer arithmetics
    ... through an AVL tree that managed void* data. ... the C standard does not. ... My frist thought was actually to store into the tree pointers to array ...
    (comp.lang.c)