After twenty years of programming in C, I thought I understood the
language pretty well until some new code I was writing started emitting
"type-punned pointer" aliasing warnings. So I read up on the problem so
I would understand it. I understand that is necessary to restrict
aliasing in order to optimize/load stores.
My question is if my solution to the problem is valid. Basically, I had
some functionality I wanted to abstract which became the following function:
int reallocItems(void **items, int itemSize, int *itemAlloc, int
numItems, int newItems, int itemHint)
{
void *rcAlloc;
int emptyItems, allocItems;
// for idempotence
allocItems = *itemAlloc;
// will the new entries fit?
//
emptyItems = allocItems - numItems;
if (newItems > emptyItems) {
// allocate the number of entries needed or the hint, whichever
is more
//
allocItems = numItems + newItems;
if (itemHint > allocItems) {
allocItems = itemHint;
}
rcAlloc = (void *) realloc(*items, allocItems * itemSize);
if (rcAlloc) {
*items = rcAlloc;
*itemAlloc = allocItems;
} else {
return -1;
}
}
return 0;
}
Naturally, when I started trying to call this function, I started
getting the type-punned pointer aliasing warnings. The code in question
looked roughly like this:
static opt_param_t *shrtOpts, *longOpts;
rc = reallocItems((void **) &shrtOpts, sizeof(opt_param_t),
&shrtOptAlloc, numShrtOpts, newShrtOpts, shrtOptHint);
Obviously, this breaks the aliasing rules. I read that I could work
around this by casting through a union. I settled on this approach, but
I'm not sure if it is valid, or if I'm merely masking the problem:
typedef union _opt_param_alias_t {
opt_param_t *o;
void *v;
} opt_param_alias_t;
rc = reallocItems(&((opt_param_alias_t *) &shrtOpts)->v,
sizeof(opt_param_t), &shrtOptAlloc, numShrtOpts, newShrtOpts, shrtOptHint)
Will casting through this union force the compiler to reload the address
of shrtOpts when I try to reference it a few lines later? Is this
solution correct? Is there a better approach that does NOT involve
changing reallocItems to return a void pointer?
I tried several different approaches, and I'm trying to find an approach
that requires little extra code and does not ugly things up too much.
Please advise. Thank you.
Regards,
Rob