Groups | Search | Server Info | Keyboard shortcuts | Login | Register [http] [https] [nntp] [nntps]
Groups > comp.lang.c > #29104 > unrolled thread
| Started by | Jack <junw2000@gmail.com> |
|---|---|
| First post | 2012-12-09 23:30 -0800 |
| Last post | 2012-12-10 12:47 +0000 |
| Articles | 4 — 4 participants |
Back to article view | Back to comp.lang.c
A cast question Jack <junw2000@gmail.com> - 2012-12-09 23:30 -0800
Re: A cast question Ian Collins <ian-news@hotmail.com> - 2012-12-10 21:00 +1300
Re: A cast question Prathamesh Kulkarni <bilbotheelffriend@gmail.com> - 2012-12-10 03:39 -0800
Re: A cast question Ben Bacarisse <ben.usenet@bsb.me.uk> - 2012-12-10 12:47 +0000
| From | Jack <junw2000@gmail.com> |
|---|---|
| Date | 2012-12-09 23:30 -0800 |
| Subject | A cast question |
| Message-ID | <16311418-f133-4115-bb15-92575637d2c3@googlegroups.com> |
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
[toc] | [next] | [standalone]
| From | Ian Collins <ian-news@hotmail.com> |
|---|---|
| Date | 2012-12-10 21:00 +1300 |
| Message-ID | <ailj5nFq3nrU2@mid.individual.net> |
| In reply to | #29104 |
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
[toc] | [prev] | [next] | [standalone]
| From | Prathamesh Kulkarni <bilbotheelffriend@gmail.com> |
|---|---|
| Date | 2012-12-10 03:39 -0800 |
| Message-ID | <224a4d8f-762b-4ed0-b97e-c60516c30acd@googlegroups.com> |
| In reply to | #29104 |
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
[toc] | [prev] | [next] | [standalone]
| From | Ben Bacarisse <ben.usenet@bsb.me.uk> |
|---|---|
| Date | 2012-12-10 12:47 +0000 |
| Message-ID | <0.5e7819f471265492e26e.20121210124736GMT.877goqm5uf.fsf@bsb.me.uk> |
| In reply to | #29104 |
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.
[toc] | [prev] | [standalone]
Back to top | Article view | comp.lang.c
csiph-web