Re: A question about void pointers



Richard Harter wrote:
On Mon, 01 Dec 2008 13:02:34 -0500, Eric Sosman
<Eric.Sosman@xxxxxxx> wrote:

Richard Harter wrote:
Here is a simple problem. In the calling environment there is a pointer to some data, e.g., an arrays of structs with a declaration that looks something like this:

struct rabbit *peter, *molly;
We have a function that will alter the data and change the pointers. We might call it like this:

carrot_patch(&peter,&molly);
Suppose carrot_patch is some kind of generic function that can
operate on data of many different types? It would be nice if
the prototype had generic pointers, e.g.,

void carrot_patch(void *, void *);
Okay. Just keep in mind that the two parameters point at the
pointer variables `peter' and `molly', and not to `struct rabbit'
instances.

Fine so far. In the code for function carrot_patch we have a
little issue. How is it going to handle these pointers to
pointers?
There are two (plausible) things it could do: It could
"handle" them blindly, just passing them around as "pointers
to whatever," or it could somehow determine that they in fact
point to `struct rabbit*' pointers, convert them appropriately,
and then use and/or modify the pointed-at pointers (`peter' and
`molly'). In the latter case, it could also use those pointers
to get at the `struct rabbit' instances they in turn point at.

The continuation was meant to rule out the latter possibility.
As far as carrot_patch is concerned the pointers are pointers to
raw storage objects.

Then you're out of luck: C has no "generic pointer to pointer"
type, so there's no way for carrot_patch() to know how many bytes
its arguments point to nor how to interpret them. There are N cases:

1) `char*' and `void*' have the same size and representation

2) All pointers to complete or incomplete struct types have
the same size and representation

3) All pointers to complete or incomplete union types have
the same size and representation

4,5,...,N) Pointers to other types can have any sizes and
representations the implementation feels like using

On many systems it will turn out that all of (1) through (N)
devolve to a single representation that works for all pointed-to
types, but this is not something the C language guarantees, and
there have been systems where different pointer types have different
representations.

[...]
The actual code is a bit of code to resize an array of structs;
however it could just as well be to encrypt them. Be that as it
may, here is what I ended up writing.


static void
exparray(char **a, size_t *a_sz, size_t d_sz)
{
size_t keep;
size_t sz;
size_t newb;

trace("exparray");
sz = *a_sz;
keep = sz*d_sz;
if (sz <4) sz = 4;
else if (sz < 32) sz *= 2;
else sz += sz/2;
newb = sz*d_sz;
*a_sz = sz;
*a = morespace(*a,keep,newb,LINELOC);
}

with example usage

exparray((char **)&(src->ct),&src->sz_ct,sizeof(CONTABLE));

[src->ct is of type CONTABLE *, src->ct is the table size,
LINELOC is a macro concatenating file name and line number,
and morespace is an allocator routine that resizes a storage
object that takes care of things like failures.]

Since `char*' and `CONTABLE*' may have different sizes and
representations, both references to `*a' in the last statement
are suspect. They rely not on the C language, but on peculiarities
of particular C implementations, and are not guaranteed to work
as you desire.

When exparray is called it determines a new table size, allocates
space for the new table, copies in the old table, and changes the
table pointer and table size in the calling routine.

The morespace prototype is (void *)morespace(void *,size_t,size_t,char *,
i.e., it takes a generic pointer and returns one. I could play
the same trick with exparray, but that's not nice for a couple or
reasons. The quoted code isn't nice either because of the (char **) cast. What would be nice is usage that looks like


exparray(&(src->ct),&src->sz_ct,sizeof(CONTABLE));

with a prototype

void exparray(void *, size_t *,size_t)

without any hackery inside.

If you know that the arrays being resized are always arrays
of structs, you can take advantage of guarantee (2) above. But
by using a `void*' as the first parameter you give up any chance
of getting the compiler to enforce your "must be a struct pointer"
requirement.

Have you considered passing a pointer to the `src' object (a
sort of "array descriptor," it appears) instead of individual
pointers to bits and pieces of its contents?

--
Eric.Sosman@xxxxxxx
.



Relevant Pages

  • Re: Simple question, err... I think
    ... Your nodes contain no other indication of which pointers are valid, ... struct CountedObject ... int is_red; ... bool lament(char const s) ...
    (comp.programming)
  • Re: big-little
    ... so, the gain is a type-system where I can use raw pointers, do most other things one can do with raw pointers, run type-checks on whatever, where adding types is often as simple as coming up with a name for it. ... similarly, one can register a few callbacks and add new types of built-in objects to the language, ... ... theoretically, one can just shove a lambda into a function pointer (say, in a struct or similar) and it should work, but I don't currently trust this all that well. ... C code generation can be skipped if one doesn't really need transparent C -> script calls (and can live with making API calls, or writing wrapper functions for said API calls...). ...
    (comp.arch)
  • Re: porting problems encountered
    ... Tru64 compiles long variables to size 8 bytes while VMS and HP-UX ... platform, the size of the structure would be 12 bytes. ... when it got to the AS/400 with 128 bit pointers. ... Using the struct from before: ...
    (comp.os.vms)
  • Re: strict aliasing rules in ISO C, someone understands them ?
    ... I understand now that my interpretation of the standard was totally ... an aggregate is a struct or an array. ... struct s1 {int i; double d;}; ... Pointers are just a means of accessing the objects, ...
    (comp.lang.c)
  • Re: Array of pointers in a struct
    ... >typedef struct trieNode ... This is an array of 27 pointers. ... >And this is the code I make a new trie node, initialize and return it. ...
    (comp.lang.c)