Jack <> writes:
> In the following code (taken from a book):
>
> struct Class {
> size_t size;
> void * (* ctor) (void * self, va_list * app);
> void * (* dtor) (void * self);
> void * (* clone) (const void * self);
> int (* differ) (const void * self, const void * b);
> };
>
> void * new (const void * _class, ...)
> {
> const struct Class * class = _class;
> void * p = calloc(1, class —> size);
>
> * (const struct Class **) p = class; //LINE1
> if (class —> ctor)
> { va_list ap;
> va_start(ap, _class);
> p = class —> ctor(p, & ap);
> va_end(ap);
> }
> return p;
> }
>
> At LINE1, why cast P to (const struct Class **) first, then deference it?
> Is not LINE1 equal to the following line?
>
> (const struct Class *) p = class;
As has been said, no. You can't assign to a cast expression.
But this code is pretty gruesome! It would be much clearer if the
intent were made plain. The idea is that every class instance starts
with a pointer to a struct describing the class. There is no need to
lie about that -- you can "over allocate" perfectly legally, so the
author could have written:
struct ClassInstance {
struct Class *class;
};
and in new:
const struct Class *class = _class;
struct ClassInstance *inst = calloc(1, class->size);
inst->class = class;
if (class->ctor)
{ va_list ap;
va_start(ap, _class);
inst = class->ctor(inst, &ap);
va_end(ap);
}
return inst;
(and I'd change the return type, too).
Depending on the rest of the code, it's possible that the lie (called
type punning) might even break on some odd architectures.
--
Ben.
|