Velocity Reviews

Velocity Reviews (http://www.velocityreviews.com/forums/index.php)
-   C Programming (http://www.velocityreviews.com/forums/f42-c-programming.html)
-   -   A cast question (http://www.velocityreviews.com/forums/t955303-a-cast-question.html)

Jack 12-10-2012 07:30 AM

A cast question
 
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;


Thanks.

Jack

Ian Collins 12-10-2012 08:00 AM

Re: A cast question
 
Jack wrote:
> 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;


No, the above isn't valid syntax (see the earlier "Casts on lvalues"
thread for the gore). Even if it were valid, it would change the value
of p rather than saving the value of class in the memory pointed to by p.

They could have written

const struct Class** p = calloc( 1, class->size );

*p = class;

--
Ian Collins

Prathamesh Kulkarni 12-10-2012 11:39 AM

Re: A cast question
 
On Monday, 10 December 2012 02:30:43 UTC-5, Jack wrote:
> 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 you intend to use p as pointer to pointer to
struct Class, shouldn't it be
void *p = calloc(1, sizeof(struct Class *)); ?

>
> 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;
>
>
>
>
>
> Thanks.
>
>
>
> Jack



Ben Bacarisse 12-10-2012 12:47 PM

Re: A cast question
 
Jack <junw2000@gmail.com> 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.


All times are GMT. The time now is 02:01 AM.

Powered by vBulletin®. Copyright ©2000 - 2014, vBulletin Solutions, Inc.
SEO by vBSEO ©2010, Crawlability, Inc.