Velocity Reviews - Computer Hardware Reviews

Velocity Reviews > Newsgroups > Programming > C Programming > structure and constant memebers

Reply
Thread Tools

structure and constant memebers

 
 
Dave Thompson
Guest
Posts: n/a
 
      10-17-2005
On 05 Oct 2005 07:31:56 -0700, Tim Rentsch <(E-Mail Removed)>
wrote:
<snip>
> It is possible to construct a struct with const members in a
> malloc'ed space, without UB. (Disclaimer: code has not been
> compiled.)
>
> ... #includes as needed ...
>
> struct thing {
> int a;
> const int b;
> int c;
> };
>
> struct thing *
> malloc_thing( int a, int b, int c ){
> void *v;
> struct thing *r;
>
> r = v = malloc( sizeof *r );
> if( !r ) exit( EXIT_FAILURE ); /* whatever... */
>
> r->a = a;
> *(int*) ((char*)v + offsetof(struct thing, b)) = b;
> r->c = c;
> return r;
> }
>

There's no need for v and offsetof; &r->b and (int*)&r->b are fine.

> Some people might squawk about the '(int*)' cast; they might want to
> use
>

No one should object to the cast as such, which is clearly a pointer
(value) to a correctly allocated and aligned object. What some might
object to is storing through that pointer, on the grounds the lvalue
being used is not suitable for the actual object, although I believe
in this case the "untypedness" of malloc-ed space saves us.

> memcpy( (char*)v + offsetof(struct thing, b), &b, sizeof r->b );
>
> instead.


Ditto, except (anynonconst*)&r->b is sufficient to pass to void* ,
and void* specifically might be considered good documentation.
Yes, this should squash the "wrong type for object" objection.

- David.Thompson1 at worldnet.att.net
 
Reply With Quote
 
 
 
 
Tim Rentsch
Guest
Posts: n/a
 
      10-18-2005
Dave Thompson <(E-Mail Removed)> writes:

> On 05 Oct 2005 07:31:56 -0700, Tim Rentsch <(E-Mail Removed)>
> wrote:
> <snip>
> > It is possible to construct a struct with const members in a
> > malloc'ed space, without UB. (Disclaimer: code has not been
> > compiled.)
> >
> > ... #includes as needed ...
> >
> > struct thing {
> > int a;
> > const int b;
> > int c;
> > };
> >
> > struct thing *
> > malloc_thing( int a, int b, int c ){
> > void *v;
> > struct thing *r;
> >
> > r = v = malloc( sizeof *r );
> > if( !r ) exit( EXIT_FAILURE ); /* whatever... */
> >
> > r->a = a;
> > *(int*) ((char*)v + offsetof(struct thing, b)) = b;
> > r->c = c;
> > return r;
> > }
> >

> There's no need for v and offsetof; &r->b and (int*)&r->b are fine.


Yes, good point. The truth is, I just forgot about these, because my
own development practices are so strongly predisposed to never
"casting away" const-ness.

Incidentally, why did you say "&r->b and (int*)&r->b"? Only
one expression (the second one) would be used.


> > Some people might squawk about the '(int*)' cast; they might want to
> > use
> >

> No one should object to the cast as such, which is clearly a pointer
> (value) to a correctly allocated and aligned object. What some might
> object to is storing through that pointer, on the grounds the lvalue
> being used is not suitable for the actual object, although I believe
> in this case the "untypedness" of malloc-ed space saves us.


I believe no reasonable person would object either to the '(int *)'
cast or to storing through the resultant pointer value. I put in
the alternative only to avoid an irrelevant tangential discussion
about the possible legalities or non-legalities. Not that such
nitpicking would ever occur in comp.lang.c.


> > memcpy( (char*)v + offsetof(struct thing, b), &b, sizeof r->b );
> >
> > instead.

>
> Ditto, except (anynonconst*)&r->b is sufficient to pass to void* ,
> and void* specifically might be considered good documentation.
> Yes, this should squash the "wrong type for object" objection.


Legally, you're right.

Stylistically, writing '(void*) &r->b' fails my "what reaction would I
expect during code review?" test. It works, but for reasons that are
deceptive or at best obscure. An alternative that might be better:

#define dangerous_memcpy(d,s,n) (memcpy( (void*)(d), (s), (n) ))

...

dangerous_memcpy( &r->b, &b, sizeof r->b );

 
Reply With Quote
 
 
 
 
Dave Thompson
Guest
Posts: n/a
 
      10-24-2005
On 17 Oct 2005 19:36:13 -0700, Tim Rentsch <(E-Mail Removed)>
wrote:

> Dave Thompson <(E-Mail Removed)> writes:
>
> > On 05 Oct 2005 07:31:56 -0700, Tim Rentsch <(E-Mail Removed)>

<snip>
> > > *(int*) ((char*)v + offsetof(struct thing, b)) = b;

<snip>
> > There's no need for v and offsetof; &r->b and (int*)&r->b are fine.

>
> Yes, good point. The truth is, I just forgot about these, because my
> own development practices are so strongly predisposed to never
> "casting away" const-ness.
>
> Incidentally, why did you say "&r->b and (int*)&r->b"? Only
> one expression (the second one) would be used.
>

Well, the latter includes the former so you're using both. <G> I have
a bias toward generalizing or noting related cases so as to avoid
implication that because I omitted something it isn't covered or isn't
the same, especially with my delay in reading and replying to news.
But I agree the latter is the one whose validity is (more) important.

>
> > > Some people might squawk about the '(int*)' cast; they might want to
> > > use
> > >

> > No one should object to the cast as such, which is clearly a pointer
> > (value) to a correctly allocated and aligned object. What some might
> > object to is storing through that pointer, on the grounds the lvalue
> > being used is not suitable for the actual object, although I believe
> > in this case the "untypedness" of malloc-ed space saves us.

>
> I believe no reasonable person would object either to the '(int *)'
> cast or to storing through the resultant pointer value. I put in
> the alternative only to avoid an irrelevant tangential discussion
> about the possible legalities or non-legalities. Not that such
> nitpicking would ever occur in comp.lang.c.
>

I think both objections are wrong, but distinguishable. The pointer
(value) cast is to my reading clearly allowed by direct positive
wording; I don't see _any_ counterargument. The store on its face
triggers the rules about storing into objects and particularly const
objects. In practice the fact that malloc space must be contiguous and
most of it writable means that an implementation couldn't enforce
constness of a subobject in it, and I _think_ the formal reflection of
this should be read to formally affirm it, but I can see that a
counterargument _could_ be made.

<snip: or memcpy>
> > Ditto, except (anynonconst*)&r->b is sufficient to pass to void* ,
> > and void* specifically might be considered good documentation.
> > Yes, this should squash the "wrong type for object" objection.

>
> Legally, you're right.
>
> Stylistically, writing '(void*) &r->b' fails my "what reaction would I
> expect during code review?" test. It works, but for reasons that are
> deceptive or at best obscure. An alternative that might be better:
>

I'm not sure about that. Semantically, I need to pass to memcpy a
pointer to the memory as nonconst but I don't otherwise care _here_
about the type. I think void* expresses that reasonably, and so does
char*. And so does int*, except it does care about the type. If there
were a shop or project style applicable to this I would conform, but I
don't see anything a priori bad about any of these.

> #define dangerous_memcpy(d,s,n) (memcpy( (void*)(d), (s), (n) ))
>

That's certainly an option, although I would probably go with a macro
only if this situation occurs more than a few times in the code --
which I hope it doesn't.

- David.Thompson1 at worldnet.att.net
 
Reply With Quote
 
Tim Rentsch
Guest
Posts: n/a
 
      10-26-2005
Dave Thompson <(E-Mail Removed)> writes:

> On 17 Oct 2005 19:36:13 -0700, Tim Rentsch <(E-Mail Removed)>
> wrote:
>
> > Dave Thompson <(E-Mail Removed)> writes:
> >

> <snip: or memcpy>
> > > Ditto, except (anynonconst*)&r->b is sufficient to pass to void* ,
> > > and void* specifically might be considered good documentation.
> > > Yes, this should squash the "wrong type for object" objection.

> >
> > Legally, you're right.
> >
> > Stylistically, writing '(void*) &r->b' fails my "what reaction would I
> > expect during code review?" test. It works, but for reasons that are
> > deceptive or at best obscure. An alternative that might be better:
> >

> I'm not sure about that. Semantically, I need to pass to memcpy a
> pointer to the memory as nonconst but I don't otherwise care _here_
> about the type. I think void* expresses that reasonably, and so does
> char*. And so does int*, except it does care about the type. If there
> were a shop or project style applicable to this I would conform, but I
> don't see anything a priori bad about any of these.


Actually I think we might be closer on this than it might seem.
By my question, I don't mean that I think it would fail the code
review necessarily, only that it might be brought up; if I can
avoid spending code review capital on this line, there's more to
spend other places. So the code review test question can be seen
as overly stringent; but sometimes it's good to be more
stringent than is strictly necessary.
 
Reply With Quote
 
 
 
Reply

Thread Tools

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is On
HTML code is Off
Trackbacks are On
Pingbacks are On
Refbacks are Off


Similar Threads
Thread Thread Starter Forum Replies Last Post
pointers to constant characters and constant pointers to characters sam_cit@yahoo.co.in C Programming 4 12-14-2006 11:10 PM
structure and constant memebers ravinder thakur C++ 1 10-04-2005 10:20 AM
can I use a pointer to step through memebers of structures? G Patel C Programming 8 02-07-2005 08:49 PM
"Non-constant" constant can't be used as template argument Martin Magnusson C++ 2 10-08-2004 08:41 AM
Understanding How To Use #ifdef Constant #define Constant Sequence In Multible Files Christopher M. Lusardi C++ 1 09-02-2004 07:43 AM



Advertisments