Groups | Search | Server Info | Keyboard shortcuts | Login | Register [http] [https] [nntp] [nntps]


Groups > comp.lang.c > #30504 > unrolled thread

Initializing a malloc'ed struct whose fields are const with run-time values

Started byNoob <root@127.0.0.1>
First post2013-01-22 16:36 +0100
Last post2013-01-22 20:48 -0800
Articles 20 on this page of 64 — 13 participants

Back to article view | Back to comp.lang.c


Contents

  Initializing a malloc'ed struct whose fields are const with run-time values Noob <root@127.0.0.1> - 2013-01-22 16:36 +0100
    Re: Initializing a malloc'ed struct whose fields are const with run-time values Shao Miller <sha0.miller@gmail.com> - 2013-01-22 11:23 -0500
      Re: Initializing a malloc'ed struct whose fields are const with run-time values Ben Bacarisse <ben.usenet@bsb.me.uk> - 2013-01-22 21:26 +0000
        Re: Initializing a malloc'ed struct whose fields are const with run-time values James Kuyper <jameskuyper@verizon.net> - 2013-01-22 16:41 -0500
      Re: Initializing a malloc'ed struct whose fields are const with run-time values William Ahern <william@wilbur.25thandClement.com> - 2013-01-22 13:25 -0800
        Re: Initializing a malloc'ed struct whose fields are const with run-time values Shao Miller <sha0.miller@gmail.com> - 2013-01-22 23:17 -0500
      Re: Initializing a malloc'ed struct whose fields are const with run-time values Ben Bacarisse <ben.usenet@bsb.me.uk> - 2013-01-23 13:09 +0000
        Re: Initializing a malloc'ed struct whose fields are const with run-time values Noob <root@127.0.0.1> - 2013-01-23 14:16 +0100
          Re: Initializing a malloc'ed struct whose fields are const with run-time values "BartC" <bc@freeuk.com> - 2013-01-23 13:25 +0000
            Re: Initializing a malloc'ed struct whose fields are const with run-time values Noob <root@127.0.0.1> - 2013-01-23 15:21 +0100
              Re: Initializing a malloc'ed struct whose fields are const with run-time values Ben Bacarisse <ben.usenet@bsb.me.uk> - 2013-01-23 14:56 +0000
                Re: Initializing a malloc'ed struct whose fields are const with run-time values Noob <root@127.0.0.1> - 2013-01-23 16:40 +0100
                  Re: Initializing a malloc'ed struct whose fields are const with run-time values Ben Bacarisse <ben.usenet@bsb.me.uk> - 2013-01-23 18:26 +0000
                  Re: Initializing a malloc'ed struct whose fields are const with run-time values Tim Rentsch <txr@alumni.caltech.edu> - 2013-01-23 20:39 -0800
              Re: Initializing a malloc'ed struct whose fields are const with run-time values Shao Miller <sha0.miller@gmail.com> - 2013-01-23 17:14 -0500
    Re: Initializing a malloc'ed struct whose fields are const with run-time values Ike Naar <ike@sverige.freeshell.org> - 2013-01-22 17:59 +0000
      Re: Initializing a malloc'ed struct whose fields are const with run-time values Shao Miller <sha0.miller@gmail.com> - 2013-01-22 14:09 -0500
        Re: Initializing a malloc'ed struct whose fields are const with run-time values Noob <root@localhost> - 2013-01-22 21:59 +0100
          Re: Initializing a malloc'ed struct whose fields are const with run-time values glen herrmannsfeldt <gah@ugcs.caltech.edu> - 2013-01-22 21:19 +0000
          Re: Initializing a malloc'ed struct whose fields are const with run-time values Shao Miller <sha0.miller@gmail.com> - 2013-01-22 23:47 -0500
        Re: Initializing a malloc'ed struct whose fields are const with run-time values Ben Bacarisse <ben.usenet@bsb.me.uk> - 2013-01-22 21:05 +0000
          Re: Initializing a malloc'ed struct whose fields are const with run-time values Shao Miller <sha0.miller@gmail.com> - 2013-01-22 16:15 -0500
      Re: Initializing a malloc'ed struct whose fields are const with   run-time values Ian Collins <ian-news@hotmail.com> - 2013-01-23 09:43 +1300
        Re: Initializing a malloc'ed struct whose fields are const with   run-time values William Ahern <william@wilbur.25thandClement.com> - 2013-01-22 13:19 -0800
          Re: Initializing a malloc'ed struct whose fields are const with   run-time values William Ahern <william@wilbur.25thandClement.com> - 2013-01-22 13:35 -0800
            Re: Initializing a malloc'ed struct whose fields are const with   run-time values Ian Collins <ian-news@hotmail.com> - 2013-01-23 10:45 +1300
              Re: Initializing a malloc'ed struct whose fields are const with   run-time values Shao Miller <sha0.miller@gmail.com> - 2013-01-22 17:07 -0500
              Re: Initializing a malloc'ed struct whose fields are const with  run-time values Tim Rentsch <txr@alumni.caltech.edu> - 2013-01-22 21:29 -0800
                Re: Initializing a malloc'ed struct whose fields are const with  run-time values Ben Bacarisse <ben.usenet@bsb.me.uk> - 2013-01-23 13:54 +0000
                  Re: Initializing a malloc'ed struct whose fields are const with  run-time values Shao Miller <sha0.miller@gmail.com> - 2013-01-23 17:08 -0500
                    Re: Initializing a malloc'ed struct whose fields are const with    run-time values Ian Collins <ian-news@hotmail.com> - 2013-01-24 11:29 +1300
                      Re: Initializing a malloc'ed struct whose fields are const with    run-time values Shao Miller <sha0.miller@gmail.com> - 2013-01-23 18:26 -0500
                        Re: Initializing a malloc'ed struct whose fields are const with      run-time values Ian Collins <ian-news@hotmail.com> - 2013-01-24 14:03 +1300
                          Re: Initializing a malloc'ed struct whose fields are const with      run-time values Shao Miller <sha0.miller@gmail.com> - 2013-01-23 23:58 -0500
                      Re: Initializing a malloc'ed struct whose fields are const with  run-time values Ben Bacarisse <ben.usenet@bsb.me.uk> - 2013-01-23 23:36 +0000
                        Re: Initializing a malloc'ed struct whose fields are const with  run-time values Ian Collins <ian-news@hotmail.com> - 2013-01-24 13:55 +1300
                          Re: Initializing a malloc'ed struct whose fields are const with  run-time values Ben Bacarisse <ben.usenet@bsb.me.uk> - 2013-01-24 02:44 +0000
                  Re: Initializing a malloc'ed struct whose fields are const with  run-time values Tim Rentsch <txr@alumni.caltech.edu> - 2013-01-23 21:39 -0800
                    Re: Initializing a malloc'ed struct whose fields are const with  run-time values Shao Miller <sha0.miller@gmail.com> - 2013-01-24 00:54 -0500
                    Re: Initializing a malloc'ed struct whose fields are const with  run-time values Ben Bacarisse <ben.usenet@bsb.me.uk> - 2013-01-24 17:56 +0000
                      Re: Initializing a malloc'ed struct whose fields are const with  run-time values Tim Rentsch <txr@alumni.caltech.edu> - 2013-01-24 13:58 -0800
          Re: Initializing a malloc'ed struct whose fields are const with   run-time values James Kuyper <jameskuyper@verizon.net> - 2013-01-22 16:37 -0500
            Re: Initializing a malloc'ed struct whose fields are const with  run-time values Tim Rentsch <txr@alumni.caltech.edu> - 2013-01-22 21:22 -0800
        Re: Initializing a malloc'ed struct whose fields are const with  run-time values Tim Rentsch <txr@alumni.caltech.edu> - 2013-01-22 21:06 -0800
          Re: Initializing a malloc'ed struct whose fields are const with  run-time values Ian Collins <ian-news@hotmail.com> - 2013-01-23 19:55 +1300
            Re: Initializing a malloc'ed struct whose fields are const with  run-time values Tim Rentsch <txr@alumni.caltech.edu> - 2013-01-23 00:48 -0800
              Re: Initializing a malloc'ed struct whose fields are const with  run-time values Ian Collins <ian-news@hotmail.com> - 2013-01-23 23:06 +1300
      Re: Initializing a malloc'ed struct whose fields are const with run-time values Ben Bacarisse <ben.usenet@bsb.me.uk> - 2013-01-22 21:02 +0000
        Re: Initializing a malloc'ed struct whose fields are const with run-time values Shao Miller <sha0.miller@gmail.com> - 2013-01-22 16:12 -0500
          Re: Initializing a malloc'ed struct whose fields are const with run-time values Ben Bacarisse <ben.usenet@bsb.me.uk> - 2013-01-22 22:37 +0000
            Re: Initializing a malloc'ed struct whose fields are const with run-time values Shao Miller <sha0.miller@gmail.com> - 2013-01-22 22:29 -0500
              Re: Initializing a malloc'ed struct whose fields are const with run-time values Ben Bacarisse <ben.usenet@bsb.me.uk> - 2013-01-23 04:28 +0000
                Re: Initializing a malloc'ed struct whose fields are const with run-time values Shao Miller <sha0.miller@gmail.com> - 2013-01-23 00:07 -0500
                  Re: Initializing a malloc'ed struct whose fields are const with run-time values Ben Bacarisse <ben.usenet@bsb.me.uk> - 2013-01-23 14:04 +0000
      Re: Initializing a malloc'ed struct whose fields are const with run-time values Noob <root@localhost> - 2013-01-22 22:10 +0100
    Re: Initializing a malloc'ed struct whose fields are const with run-time values Ben Bacarisse <ben.usenet@bsb.me.uk> - 2013-01-22 21:13 +0000
      Re: Initializing a malloc'ed struct whose fields are const with run-time values Shao Miller <sha0.miller@gmail.com> - 2013-01-22 16:25 -0500
        Re: Initializing a malloc'ed struct whose fields are const with run-time values Ben Bacarisse <ben.usenet@bsb.me.uk> - 2013-01-22 22:21 +0000
      Re: Initializing a malloc'ed struct whose fields are const with run-time values William Ahern <william@wilbur.25thandClement.com> - 2013-01-22 13:32 -0800
        Re: Initializing a malloc'ed struct whose fields are const with run-time values Ben Bacarisse <ben.usenet@bsb.me.uk> - 2013-01-23 03:50 +0000
      Re: Initializing a malloc'ed struct whose fields are const with run-time values Nick Bowler <nbowler@draconx.ca> - 2013-01-22 21:43 +0000
        Re: Initializing a malloc'ed struct whose fields are const with run-time values Ben Bacarisse <ben.usenet@bsb.me.uk> - 2013-01-23 03:45 +0000
          Re: Initializing a malloc'ed struct whose fields are const with run-time values Keith Thompson <kst-u@mib.org> - 2013-01-24 08:23 -0800
    Re: Initializing a malloc'ed struct whose fields are const with run-time values Tim Rentsch <txr@alumni.caltech.edu> - 2013-01-22 20:48 -0800

Page 1 of 4  [1] 2 3 4  Next page →


#30504 — Initializing a malloc'ed struct whose fields are const with run-time values

FromNoob <root@127.0.0.1>
Date2013-01-22 16:36 +0100
SubjectInitializing a malloc'ed struct whose fields are const with run-time values
Message-ID<kdmbl7$4lc$1@dont-email.me>
Hello,

Is it possible, in standard C89 and C99, to initialize a
struct whose fields are const with values only known at
run-time?

For example, consider:

  struct toto { const int i; const float f; const void *p; };

Is it possible to portably implement:

  struct toto *foo(int i, float f, void *p);

which allocates space for a "struct toto", initializes it
with i, f, p and returns the address of this struct?

The best I could come up with is:

#include <stdlib.h>
#include <string.h>
struct toto *foo(int i, float f, void *p)
{
  struct toto s = { i, f, p };
  struct toto *res = malloc(sizeof *res);
  if (res != NULL) memcpy(res, &s, sizeof s);
  return res;
}

which has several defects:

1) Apparently, C89 does not allow one to use elements "not computable
at load time" in an initialization list. However, it is allowed both
in C99 (right?) and in gnu89.

2) I'm not sure it is well-defined to memcpy stuff into some const
fields. Does it tickle the cranky UB gods?

Regards.

[toc] | [next] | [standalone]


#30507

FromShao Miller <sha0.miller@gmail.com>
Date2013-01-22 11:23 -0500
Message-ID<kdmee8$q6t$1@dont-email.me>
In reply to#30504
On 1/22/2013 10:36, Noob wrote:
> Hello,
>
> Is it possible, in standard C89 and C99, to initialize a
> struct whose fields are const with values only known at
> run-time?
>
> For example, consider:
>
>    struct toto { const int i; const float f; const void *p; };
>

There is probably a better example, since none of the members here are 
non-'const'.  You could just have these members non-'const'-qualified 
and return a 'const struct toto *', possibly with a cast.  I'll assume 
you have at least one non-'const' member for further discussion.

> Is it possible to portably implement:
>
>    struct toto *foo(int i, float f, void *p);
>
> which allocates space for a "struct toto", initializes it
> with i, f, p and returns the address of this struct?
>
> The best I could come up with is:
>
> #include <stdlib.h>
> #include <string.h>
> struct toto *foo(int i, float f, void *p)
> {
>    struct toto s = { i, f, p };
>    struct toto *res = malloc(sizeof *res);
>    if (res != NULL) memcpy(res, &s, sizeof s);
>    return res;
> }
>

How about:

   #include <stddef.h>
   #include <stdlib.h>

   struct toto {
       const int i;
       const float f;
       const void * p;
     };

   struct toto * foo(int i, float f, void * p) {
       unsigned char * obj;

       obj = malloc(sizeof (struct toto));
       if (obj) {
           *(int *) (obj + offsetof(struct toto, i)) = i;
           *(float *) (obj + offsetof(struct toto, f)) = f;
           *(void **) (obj + offsetof(struct toto, i)) = p;
         }
       return (void *) obj;
     }

   int main(void) {
       struct toto * test = foo(42, 3.14, NULL);
       free(test);
       return 0;
     }

> which has several defects:
>
> 1) Apparently, C89 does not allow one to use elements "not computable
> at load time" in an initialization list. However, it is allowed both
> in C99 (right?) and in gnu89.
>

The initializers in an initializer list for an aggregate or union must 
be constant expressions, and no, I do not believe that's changed in any 
newer Standard.

> 2) I'm not sure it is well-defined to memcpy stuff into some const
> fields.
>

You can 'memcpy' into allocated storage just fine.  In C >= C99, you 
need to be concerned with effective type, so it's not completely 
straight-forward.

> Does it tickle the cranky UB gods?
>

This is one of the funnier things I've read in comp.lang.c! :)

-- 
- Shao Miller
--
"Thank you for the kind words; those are the kind of words I like to hear.

Cheerily,"  -- Richard Harter

[toc] | [prev] | [next] | [standalone]


#30532

FromBen Bacarisse <ben.usenet@bsb.me.uk>
Date2013-01-22 21:26 +0000
Message-ID<0.1e6b77056cbf58d76d53.20130122212621GMT.877gn452pu.fsf@bsb.me.uk>
In reply to#30507
Shao Miller <sha0.miller@gmail.com> writes:

> On 1/22/2013 10:36, Noob wrote:
<snip>
>> 1) Apparently, C89 does not allow one to use elements "not computable
>> at load time" in an initialization list. However, it is allowed both
>> in C99 (right?) and in gnu89.
>
> The initializers in an initializer list for an aggregate or union must
> be constant expressions, and no, I do not believe that's changed in
> any newer Standard.

I think it has.

-- 
Ben.

[toc] | [prev] | [next] | [standalone]


#30538

FromJames Kuyper <jameskuyper@verizon.net>
Date2013-01-22 16:41 -0500
Message-ID<50FF078D.8000701@verizon.net>
In reply to#30532
On 01/22/2013 04:26 PM, Ben Bacarisse wrote:
> Shao Miller <sha0.miller@gmail.com> writes:
...
>> The initializers in an initializer list for an aggregate or union must
>> be constant expressions, and no, I do not believe that's changed in
>> any newer Standard.
> 
> I think it has.

You think correctly - as of C99, that restriction only applies to
initializers for objects of static storage duration. As of C2011, it
also applies to initializers for objects with thread storage duration
(6.7.9p4); only C90 imposed it on initializers for objects with
automatic storage duration.

[toc] | [prev] | [next] | [standalone]


#30534

FromWilliam Ahern <william@wilbur.25thandClement.com>
Date2013-01-22 13:25 -0800
Message-ID<tmc3t9-6br.ln1@wilbur.25thandClement.com>
In reply to#30507
Shao Miller <sha0.miller@gmail.com> wrote:
> On 1/22/2013 10:36, Noob wrote:
<snip>
> > which has several defects:
> >
> > 1) Apparently, C89 does not allow one to use elements "not computable
> > at load time" in an initialization list. However, it is allowed both
> > in C99 (right?) and in gnu89.
> >

> The initializers in an initializer list for an aggregate or union must 
> be constant expressions, and no, I do not believe that's changed in any 
> newer Standard.

I believe that changed with C99. It only applies to objects of static
storage duration. 6.7.8p4 + "exceptio probat regulam in casibus non
exceptis".

[toc] | [prev] | [next] | [standalone]


#30554

FromShao Miller <sha0.miller@gmail.com>
Date2013-01-22 23:17 -0500
Message-ID<kdno8i$oa2$1@dont-email.me>
In reply to#30534
On 1/22/2013 16:25, William Ahern wrote:
> Shao Miller <sha0.miller@gmail.com> wrote:
>> On 1/22/2013 10:36, Noob wrote:
> <snip>
>>> which has several defects:
>>>
>>> 1) Apparently, C89 does not allow one to use elements "not computable
>>> at load time" in an initialization list. However, it is allowed both
>>> in C99 (right?) and in gnu89.
>>>
>
>> The initializers in an initializer list for an aggregate or union must
>> be constant expressions, and no, I do not believe that's changed in any
>> newer Standard.
>
> I believe that changed with C99. It only applies to objects of static
> storage duration. 6.7.8p4 + "exceptio probat regulam in casibus non
> exceptis".
>

Thank you, Mr. William Ahern.

On 1/22/2013 16:26, Ben Bacarisse wrote:
> I think it has.

Thank you, Ben.

On 1/22/2013 16:41, James Kuyper wrote:
> You think correctly - as of C99, that restriction only applies to
> initializers for objects of static storage duration. As of C2011, it
> also applies to initializers for objects with thread storage duration
> (6.7.9p4); only C90 imposed it on initializers for objects with
> automatic storage duration.

Thank you, Mr. James Kuyper.

On 1/22/2013 17:21, Ben Bacarisse wrote:
> Shao Miller <sha0.miller@gmail.com> writes:
>> On 1/22/2013 16:13, Ben Bacarisse wrote:
>>> Noob <root@127.0.0.1> writes:
>>>
>>>> #include <stdlib.h>
>>>> #include <string.h>
>>>> struct toto *foo(int i, float f, void *p)
>>>> {
>>>>   struct toto s = { i, f, p };
>>>>   struct toto *res = malloc(sizeof *res);
>>>>   if (res != NULL) memcpy(res, &s, sizeof s);
>>>>   return res;
>>>> }
>>>>
>>>> [...]
>>>>
>>>> 2) I'm not sure it is well-defined to memcpy stuff into some const
>>>> fields. Does it tickle the cranky UB gods?
>>>
>>> No, I think it's fine.  You are not modifying anything that is const.
>>> malloced storage has no declared type and the memcpy probably makes the
>>> effective type a byte array.
>>
>> To Ben: I think the effective type would be 'struct toto', as 'memcpy'
>> is included in 6.5p6.
>
> Interesting!  My recollection was that memcpy would treat the
> destination as a char array but would then set the effective type for
> subsequent accesses, but the text says it sets the effective type "for
> that access and for subsequent accesses".
>
> However, I think the conclusion is still valid.  To be more specific, I
> think the effective type is a red herring -- I don't think it matters when
> determining what can and can't be modified here.
>
> The closest approach to UB that I can find is this (7.1.4 p1):
>
>   "Each of the following statements applies unless explicitly stated
>   otherwise in the detailed descriptions that follow: If an argument to
>   a function has an invalid value (such as [...] a pointer to
>   non-modifiable storage when the corresponding parameter is not
>   const-qualified) ..."
>
> But that does not apply here -- the argument is a pointer to modifiable
> storage no matter what it's (effective) type is about to become.  Of
> course, there may be some other reason why it's UB, but I can't see one.
>

My original note to Noob about effective type was not applicable to 
Noob's case, but just a warning about using 'memcpy' into allocated 
storage for C >= C99, in general.  For example, just before the 'return':

   if (res) {
       int * ip = (void *) ((char *) res + offsetof(struct toto, i));
       /* 'ip' not in bullets of 6.5p7 */
       *ip;
     }

(But I could be forgetting something else.)

-- 
- Shao Miller
--
"Thank you for the kind words; those are the kind of words I like to hear.

Cheerily,"  -- Richard Harter

[toc] | [prev] | [next] | [standalone]


#30569

FromBen Bacarisse <ben.usenet@bsb.me.uk>
Date2013-01-23 13:09 +0000
Message-ID<0.d736b4f0b2c6bcf0e089.20130123130900GMT.877gn42gib.fsf@bsb.me.uk>
In reply to#30507
Shao Miller <sha0.miller@gmail.com> writes:

> On 1/22/2013 10:36, Noob wrote:
>>
>> Is it possible, in standard C89 and C99, to initialize a
>> struct whose fields are const with values only known at
>> run-time?
>>
>> For example, consider:
>>
>>    struct toto { const int i; const float f; const void *p; };
>
> There is probably a better example, since none of the members here are
> non-'const'.

Not that it matters much but I just spotted that p is not const.  I
don't think it affects much of the discussion though, and the OP may in
fact have intended it to be.

<snip>
-- 
Ben.

[toc] | [prev] | [next] | [standalone]


#30570

FromNoob <root@127.0.0.1>
Date2013-01-23 14:16 +0100
Message-ID<kdonp9$lqb$1@dont-email.me>
In reply to#30569
Ben Bacarisse wrote:

> Shao Miller <sha0.miller@gmail.com> writes:
> 
>> On 1/22/2013 10:36, Noob wrote:
>>>
>>> Is it possible, in standard C89 and C99, to initialize a
>>> struct whose fields are const with values only known at
>>> run-time?
>>>
>>> For example, consider:
>>>
>>>    struct toto { const int i; const float f; const void *p; };
>>
>> There is probably a better example, since none of the members here are
>> non-'const'.
> 
> Not that it matters much but I just spotted that p is not const.  I
> don't think it affects much of the discussion though, and the OP may in
> fact have intended it to be.

You're right, I meant:

  struct toto { const int i; const float f; void *const p; };

And it turns out that all this work was fruitless, as gcc does not
take advantage of the const-ness of the fields, and keeps reloading
the values from memory every time they are needed...

Regards.

[toc] | [prev] | [next] | [standalone]


#30571

From"BartC" <bc@freeuk.com>
Date2013-01-23 13:25 +0000
Message-ID<sxRLs.130$2A1.117@fx10.fr7>
In reply to#30570

"Noob" <root@127.0.0.1> wrote in message news:kdonp9$lqb$1@dont-email.me...

> You're right, I meant:
> 
>  struct toto { const int i; const float f; void *const p; };
> 
> And it turns out that all this work was fruitless, as gcc does not
> take advantage of the const-ness of the fields, and keeps reloading
> the values from memory every time they are needed...

Where should it load them from instead?

Perhaps there was no opportunity to keep the values resident in registers.

-- 
Bartc

 

[toc] | [prev] | [next] | [standalone]


#30575

FromNoob <root@127.0.0.1>
Date2013-01-23 15:21 +0100
Message-ID<kdorio$e37$1@dont-email.me>
In reply to#30571
BartC wrote:

> Noob wrote:
> 
>> You're right, I meant:
>>
>>  struct toto { const int i; const float f; void *const p; };
>>
>> And it turns out that all this work was fruitless, as gcc does not
>> take advantage of the const-ness of the fields, and keeps reloading
>> the values from memory every time they are needed...
> 
> Where should it load them from instead?

I expected the compiler to write the value to a register before
the loop, and read it from there henceforth.

> Perhaps there was no opportunity to keep the values resident in registers.

If I convince the compiler that "i" will not change during the
lifetime of the function by defining a copy on the stack:

  const int i = ctx->i;
  while ( 1 ) { use i, and the rest of the ctx }

then i is indeed kept in a register (of which I have 32 on this
platform). I was hoping to sprinkle const-qualifiers in the struct
definition so that I wouldn't have to make copies of every const
field in the ctx struct.

Regards.

[toc] | [prev] | [next] | [standalone]


#30576

FromBen Bacarisse <ben.usenet@bsb.me.uk>
Date2013-01-23 14:56 +0000
Message-ID<0.0a73ff6daa9e0b443742.20130123145617GMT.87obgg0wz2.fsf@bsb.me.uk>
In reply to#30575
Noob <root@127.0.0.1> writes:

> BartC wrote:
>
>> Noob wrote:
>> 
>>> You're right, I meant:
>>>
>>>  struct toto { const int i; const float f; void *const p; };
>>>
>>> And it turns out that all this work was fruitless, as gcc does not
>>> take advantage of the const-ness of the fields, and keeps reloading
>>> the values from memory every time they are needed...
>> 
>> Where should it load them from instead?
>
> I expected the compiler to write the value to a register before
> the loop, and read it from there henceforth.
>
>> Perhaps there was no opportunity to keep the values resident in registers.
>
> If I convince the compiler that "i" will not change during the
> lifetime of the function by defining a copy on the stack:
>
>   const int i = ctx->i;
>   while ( 1 ) { use i, and the rest of the ctx }
>
> then i is indeed kept in a register (of which I have 32 on this
> platform). I was hoping to sprinkle const-qualifiers in the struct
> definition so that I wouldn't have to make copies of every const
> field in the ctx struct.

You may find that using restrict (if appropriate) gives better results
than const.  For example, given

  struct toto { int i; double d; };
   
  double f(struct toto *ctx, double *p)
  {
       double s = 0;
       for (int i = 0; i < ctx->i; i++) {
            s += ctx->d;
            *p += 1;
       }
       return s;
  }

gcc won't keep ctx->d in a register because *p might alias it.  The code
loads ctx->d every time even if cts points to a const struct with const
members.  But making both ctx and p restrict qualified does what you want.

-- 
Ben.

[toc] | [prev] | [next] | [standalone]


#30577

FromNoob <root@127.0.0.1>
Date2013-01-23 16:40 +0100
Message-ID<kdp082$chp$1@dont-email.me>
In reply to#30576
Ben Bacarisse wrote:

> Noob wrote:
> 
>> BartC wrote:
>>
>>> Noob wrote:
>>>
>>>> You're right, I meant:
>>>>
>>>>  struct toto { const int i; const float f; void *const p; };
>>>>
>>>> And it turns out that all this work was fruitless, as gcc does not
>>>> take advantage of the const-ness of the fields, and keeps reloading
>>>> the values from memory every time they are needed...
>>>
>>> Where should it load them from instead?
>>
>> I expected the compiler to write the value to a register before
>> the loop, and read it from there henceforth.
>>
>>> Perhaps there was no opportunity to keep the values resident in registers.
>>
>> If I convince the compiler that "i" will not change during the
>> lifetime of the function by defining a copy on the stack:
>>
>>   const int i = ctx->i;
>>   while ( 1 ) { use i, and the rest of the ctx }
>>
>> then i is indeed kept in a register (of which I have 32 on this
>> platform). I was hoping to sprinkle const-qualifiers in the struct
>> definition so that I wouldn't have to make copies of every const
>> field in the ctx struct.
> 
> You may find that using restrict (if appropriate) gives better results
> than const.  For example, given
> 
>   struct toto { int i; double d; };
>    
>   double f(struct toto *ctx, double *p)
>   {
>        double s = 0;
>        for (int i = 0; i < ctx->i; i++) {
>             s += ctx->d;
>             *p += 1;
>        }
>        return s;
>   }
> 
> gcc won't keep ctx->d in a register because *p might alias it.  The code
> loads ctx->d every time even if cts points to a const struct with const
> members.  But making both ctx and p restrict qualified does what you want.

I could be wrong, but I don't think this is an aliasing problem.

The prototype for the thread's entry point is
  void *start_routine(void *arg)
(In my case, arg is, in fact, a (struct toto *))

To make your example more like mine, your function "f" should only take
a single (struct toto *) parameter, in which case I'm not sure restrict-
qualifying the parameter brings much? (And is it compatible with the
expected prototype?)

Does it make sense to restrict-qualify struct fields?

I'm off to browse ISO/IEC 9899:TC3

Regards.

[toc] | [prev] | [next] | [standalone]


#30578

FromBen Bacarisse <ben.usenet@bsb.me.uk>
Date2013-01-23 18:26 +0000
Message-ID<0.f2ae95453fbc17f667f8.20130123182654GMT.87ip6n21sh.fsf@bsb.me.uk>
In reply to#30577
Noob <root@127.0.0.1> writes:

> Ben Bacarisse wrote:
>
>> Noob wrote:
>> 
>>> BartC wrote:
>>>
>>>> Noob wrote:
>>>>
>>>>> You're right, I meant:
>>>>>
>>>>>  struct toto { const int i; const float f; void *const p; };
>>>>>
>>>>> And it turns out that all this work was fruitless, as gcc does not
>>>>> take advantage of the const-ness of the fields, and keeps reloading
>>>>> the values from memory every time they are needed...
>>>>
>>>> Where should it load them from instead?
>>>
>>> I expected the compiler to write the value to a register before
>>> the loop, and read it from there henceforth.
>>>
>>>> Perhaps there was no opportunity to keep the values resident in registers.
>>>
>>> If I convince the compiler that "i" will not change during the
>>> lifetime of the function by defining a copy on the stack:
>>>
>>>   const int i = ctx->i;
>>>   while ( 1 ) { use i, and the rest of the ctx }
>>>
>>> then i is indeed kept in a register (of which I have 32 on this
>>> platform). I was hoping to sprinkle const-qualifiers in the struct
>>> definition so that I wouldn't have to make copies of every const
>>> field in the ctx struct.
>> 
>> You may find that using restrict (if appropriate) gives better results
>> than const.  For example, given
>> 
>>   struct toto { int i; double d; };
>>    
>>   double f(struct toto *ctx, double *p)
>>   {
>>        double s = 0;
>>        for (int i = 0; i < ctx->i; i++) {
>>             s += ctx->d;
>>             *p += 1;
>>        }
>>        return s;
>>   }
>> 
>> gcc won't keep ctx->d in a register because *p might alias it.  The code
>> loads ctx->d every time even if cts points to a const struct with const
>> members.  But making both ctx and p restrict qualified does what you want.
>
> I could be wrong, but I don't think this is an aliasing problem.

Quite.  I was just punting -- it may well not be an aliasing problem.

> The prototype for the thread's entry point is
>   void *start_routine(void *arg)
> (In my case, arg is, in fact, a (struct toto *))
>
> To make your example more like mine, your function "f" should only take
> a single (struct toto *) parameter, in which case I'm not sure restrict-
> qualifying the parameter brings much?

I think not, but it does depend on other pointers of course, like global
ones.  With C11 (which has a threading model) things may be different.
It's not an area I have really studied.

> (And is it compatible with the expected prototype?)

No, but you can always arrange for the entry-point to call another
function with your desired prototype.

> Does it make sense to restrict-qualify struct fields?

Absolutely.  It is possible that the compiler is having to assume
aliasing through one or more of these?

> I'm off to browse ISO/IEC 9899:TC3

-- 
Ben.

[toc] | [prev] | [next] | [standalone]


#30600

FromTim Rentsch <txr@alumni.caltech.edu>
Date2013-01-23 20:39 -0800
Message-ID<kfna9rz6vpl.fsf@x-alumni2.alumni.caltech.edu>
In reply to#30577
Noob <root@127.0.0.1> writes:

> Ben Bacarisse wrote:
>
>> Noob wrote:
>> 
>>> BartC wrote:
>>>
>>>> Noob wrote:
>>>>
>>>>> You're right, I meant:
>>>>>
>>>>>  struct toto { const int i; const float f; void *const p; };
>>>>>
>>>>> And it turns out that all this work was fruitless, as gcc
>>>>> does not take advantage of the const-ness of the fields,
>>>>> and keeps reloading the values from memory every time they
>>>>> are needed...
>>>>
>>>> Where should it load them from instead?
>>>
>>> I expected the compiler to write the value to a register before
>>> the loop, and read it from there henceforth.
>>>
>>>> Perhaps there was no opportunity to keep the values resident in registers.
>>>
>>> If I convince the compiler that "i" will not change during the
>>> lifetime of the function by defining a copy on the stack:
>>>
>>>   const int i = ctx->i;
>>>   while ( 1 ) { use i, and the rest of the ctx }
>>>
>>> then i is indeed kept in a register (of which I have 32 on this
>>> platform). I was hoping to sprinkle const-qualifiers in the struct
>>> definition so that I wouldn't have to make copies of every const
>>> field in the ctx struct.
>> 
>> You may find that using restrict (if appropriate) gives better
>> results than const.  For example, given
>> 
>>   struct toto { int i; double d; };
>>    
>>   double f(struct toto *ctx, double *p)
>>   {
>>        double s = 0;
>>        for (int i = 0; i < ctx->i; i++) {
>>             s += ctx->d;
>>             *p += 1;
>>        }
>>        return s;
>>   }
>> 
>> gcc won't keep ctx->d in a register because *p might alias it.
>> The code loads ctx->d every time even if cts points to a const
>> struct with const members.  But making both ctx and p restrict
>> qualified does what you want.
>
> I could be wrong, but I don't think this is an aliasing
> problem.

This comment seems to me peculiar.  Do you mean you think there
isn't any aliasing going on, or that you think the compiler is
smart enough to realize there isn't any aliasing going on?  There
is a big difference between those two circumstances.

> The prototype for the thread's entry point is
>   void *start_routine(void *arg)
> (In my case, arg is, in fact, a (struct toto *))
>
> To make your example more like mine, your function "f" should
> only take a single (struct toto *) parameter, in which case I'm
> not sure restrict-qualifying the parameter brings much? (And
> is it compatible with the expected prototype?)

If you have a function declared, for example, as

    void * blah( struct whatever * );

that is compatible with defining the function thusly

    void *
    blah( struct whatever * restrict it ){  ...  }

because of how top-level qualifiers are treated for function
parameters.

> Does it make sense to restrict-qualify struct fields?

Unlikely.  Probably not impossible, but almost certainly
not a path that will help solve the problem you are
interested in solving here.

[toc] | [prev] | [next] | [standalone]


#30582

FromShao Miller <sha0.miller@gmail.com>
Date2013-01-23 17:14 -0500
Message-ID<kdpnbj$79e$2@dont-email.me>
In reply to#30575
On 1/23/2013 09:21, Noob wrote:
> BartC wrote:
>
>> Noob wrote:
>>
>>> You're right, I meant:
>>>
>>>   struct toto { const int i; const float f; void *const p; };
>>>
>>> And it turns out that all this work was fruitless, as gcc does not
>>> take advantage of the const-ness of the fields, and keeps reloading
>>> the values from memory every time they are needed...
>>
>> Where should it load them from instead?
>
> I expected the compiler to write the value to a register before
> the loop, and read it from there henceforth.
>
>> Perhaps there was no opportunity to keep the values resident in registers.
>
> If I convince the compiler that "i" will not change during the
> lifetime of the function by defining a copy on the stack:
>
>    const int i = ctx->i;
>    while ( 1 ) { use i, and the rest of the ctx }
>
> then i is indeed kept in a register (of which I have 32 on this
> platform). I was hoping to sprinkle const-qualifiers in the struct
> definition so that I wouldn't have to make copies of every const
> field in the ctx struct.
>

I think it depends what's in the loop body.  Is there any chance of 
sharing it?  I was doing a bit of thinking about aliasing recently, so 
maybe something applies.

-- 
- Shao Miller
--
"Thank you for the kind words; those are the kind of words I like to hear.

Cheerily,"  -- Richard Harter

[toc] | [prev] | [next] | [standalone]


#30511

FromIke Naar <ike@sverige.freeshell.org>
Date2013-01-22 17:59 +0000
Message-ID<slrn3vfskftksd.ddo.ike@sverige.freeshell.org>
In reply to#30504
On 2013-01-22, Noob <root@127.0.0.1> wrote:
> #include <stdlib.h>
> #include <string.h>
> struct toto *foo(int i, float f, void *p)
> {
>   struct toto s = { i, f, p };
>   struct toto *res = malloc(sizeof *res);
>   if (res != NULL) memcpy(res, &s, sizeof s);

Why memcpy instead of an assignment?
    if (res != NULL) *res = s;

>   return res;
> }

And how about returning by value?

  struct toto foo(int i, float f, void *p)
  {
    struct toto res = {i, f, p};
    return res;
  }

[toc] | [prev] | [next] | [standalone]


#30514

FromShao Miller <sha0.miller@gmail.com>
Date2013-01-22 14:09 -0500
Message-ID<kdmo4v$vm5$1@dont-email.me>
In reply to#30511
On 1/22/2013 12:59, Ike Naar wrote:
> On 2013-01-22, Noob <root@127.0.0.1> wrote:
>> #include <stdlib.h>
>> #include <string.h>
>> struct toto *foo(int i, float f, void *p)
>> {
>>    struct toto s = { i, f, p };
>>    struct toto *res = malloc(sizeof *res);
>>    if (res != NULL) memcpy(res, &s, sizeof s);
>
> Why memcpy instead of an assignment?
>      if (res != NULL) *res = s;
>

Because they amount to the same thing, behind the scenes, on a few 
implementations? ;)  Lots of people still do:

   struct tag s;
   memset(&s, 0, sizeof s);

instead of:

   struct tag s = { 0 };

But the latter seems better (when possible).

>>    return res;
>> }
>
> And how about returning by value?
>
>    struct toto foo(int i, float f, void *p)
>    {
>      struct toto res = {i, f, p};
>      return res;
>    }
>

This has the same problem with the initializer list, though.

I would guess that 'malloc' was being used for lifetime considerations, 
but obviously only Noob knows.

-- 
- Shao Miller
--
"Thank you for the kind words; those are the kind of words I like to hear.

Cheerily,"  -- Richard Harter

[toc] | [prev] | [next] | [standalone]


#30522

FromNoob <root@localhost>
Date2013-01-22 21:59 +0100
Message-ID<50fefdb9$0$16499$426a34cc@news.free.fr>
In reply to#30514
Shao Miller wrote:
> On 1/22/2013 12:59, Ike Naar wrote:
>> On 2013-01-22, Noob wrote:
>>> #include <stdlib.h>
>>> #include <string.h>
>>> struct toto *foo(int i, float f, void *p)
>>> {
>>>    struct toto s = { i, f, p };
>>>    struct toto *res = malloc(sizeof *res);
>>>    if (res != NULL) memcpy(res, &s, sizeof s);
>>
>> Why memcpy instead of an assignment?
>>      if (res != NULL) *res = s;
> 
> Because they amount to the same thing, behind the scenes, on a few 
> implementations? ;)  Lots of people still do:
> 
>    struct tag s;
>    memset(&s, 0, sizeof s);
> 
> instead of:
> 
>    struct tag s = { 0 };
> 
> But the latter seems better (when possible).
> 
>>>    return res;
>>> }
>>
>> And how about returning by value?
>>
>>    struct toto foo(int i, float f, void *p)
>>    {
>>      struct toto res = {i, f, p};
>>      return res;
>>    }
>>
> 
> This has the same problem with the initializer list, though.
> 
> I would guess that 'malloc' was being used for lifetime considerations, 
> but obviously only Noob knows.

As I often do, my simplification went a bit too far, so I'll just
describe the actual use-case.
(This involves two threads on a POSIX-compliant platform.)

I have a foo_start function which malloc's space for a "context"
struct, populates the struct according to the function's parameters,
then spawns a new thread which is passed this context. (This is why
dynamic allocation must be used.)

To make matters more complex, I have a flexible array at the end of
the struct.

Basically, struct ctx is defined this way:

struct ctx {
  int file_idx;
  const char *buf;
  sem_t sem;
  char path[];
};

void *foo_run(void *arg) {
  struct ctx *ctx = arg;
  do stuff in an infinite loop, according to ctx
}

void foo_start(int param1, int param2, ...)
{
  struct ctx *ctx = malloc(sizeof *ctx + paramx);
  populate the fields of ctx;
  spawn(foo_run, ctx);
}

In my current version, I don't have any const qualifiers in my code.
I like to look at the assembly code generated by the compiler, and I
noticed that every time I need some field from ctx, the compiler has
to reload it, instead of caching the value in a register.

As far as I understand, this is expected: the address of the struct
could be stored anywhere, and any function in a different translation
unit could "pull the rug" from under me. Except that *I* wrote the
code, and I *know* (by design) that most fields in the struct do NOT
change after init.

So I set out to sprinkle a few "const" qualifiers here and there, to
see if that would convince the compiler that some optimizations are
indeed possible (I know this looks like a clear case of premature
optimization, but I figured I might as well learn something new along
the way!)

I don't think I can just const-qualify the entire struct, because
1) the prototype for a thread's entry point is imposed by POSIX
2) const-qualifying a pointer parameter is only a contract between
the user and the function's implementer, saying "my function won't
touch your preciousss struct", it doesn't say that the struct won't
be changed by something else.

Whereas, I was under the impression that a const-qualified field
means "hear, hear, this field SHALL NEVER change!"

Anyway, I'd be happy to hear the word from the regs, and/or take
this to comp.unix.programmer at some point (although I do believe
that the core of my question is a C question, not POSIX).

Regards.

[toc] | [prev] | [next] | [standalone]


#30530

Fromglen herrmannsfeldt <gah@ugcs.caltech.edu>
Date2013-01-22 21:19 +0000
Message-ID<kdmvpg$tb6$1@speranza.aioe.org>
In reply to#30522
Noob <root@localhost> wrote:

(snip)
>> This has the same problem with the initializer list, though.
 
>> I would guess that 'malloc' was being used for lifetime considerations, 
>> but obviously only Noob knows.
 
> As I often do, my simplification went a bit too far, so I'll just
> describe the actual use-case.
> (This involves two threads on a POSIX-compliant platform.)

As far as I know, the constraints on const aren't quite as strict
as Java's static final, or Fortran's PARAMETER. 

You can get away with some things that you probably shouldn't be
able to, as the compiler can't check them. 
 
> I have a foo_start function which malloc's space for a "context"
> struct, populates the struct according to the function's parameters,
> then spawns a new thread which is passed this context. (This is why
> dynamic allocation must be used.)
 
> To make matters more complex, I have a flexible array at the end of
> the struct.
 
(snip)

> In my current version, I don't have any const qualifiers in my code.
> I like to look at the assembly code generated by the compiler, and I
> noticed that every time I need some field from ctx, the compiler has
> to reload it, instead of caching the value in a register.

Have you tried with an actual const struct (with actual compile time
constants) to see what the optimizer does? Or passing such a struct
(or pointer to one) and see what it does?
 
> As far as I understand, this is expected: the address of the struct
> could be stored anywhere, and any function in a different translation
> unit could "pull the rug" from under me. Except that *I* wrote the
> code, and I *know* (by design) that most fields in the struct do NOT
> change after init.

Well, as described in another thread, there is the 'volatile' 
attribute to tell the compiler, in some sense which I won't 
describe here, that a variable could change. 

On the other hand, normal aliasing rules apply. Often the compiler
can't assume that two pointers don't point to the same (or nearby)
variables, and so can't do some optimizations that it might otherwise
do. 
 
> So I set out to sprinkle a few "const" qualifiers here and there, to
> see if that would convince the compiler that some optimizations are
> indeed possible (I know this looks like a clear case of premature
> optimization, but I figured I might as well learn something new along
> the way!)

Did it help any? Does it change with optimization (-O) level?
 
> I don't think I can just const-qualify the entire struct, because
> 1) the prototype for a thread's entry point is imposed by POSIX
> 2) const-qualifying a pointer parameter is only a contract between
> the user and the function's implementer, saying "my function won't
> touch your preciousss struct", it doesn't say that the struct won't
> be changed by something else.
 
> Whereas, I was under the impression that a const-qualified field
> means "hear, hear, this field SHALL NEVER change!"
 
> Anyway, I'd be happy to hear the word from the regs, and/or take
> this to comp.unix.programmer at some point (although I do believe
> that the core of my question is a C question, not POSIX).

-- glen

[toc] | [prev] | [next] | [standalone]


#30556

FromShao Miller <sha0.miller@gmail.com>
Date2013-01-22 23:47 -0500
Message-ID<kdnq18$vc6$1@dont-email.me>
In reply to#30522
On 1/22/2013 15:59, Noob wrote:
> Shao Miller wrote:
>> On 1/22/2013 12:59, Ike Naar wrote:
>>> On 2013-01-22, Noob wrote:
>>>> #include <stdlib.h>
>>>> #include <string.h>
>>>> struct toto *foo(int i, float f, void *p)
>>>> {
>>>>     struct toto s = { i, f, p };
>>>>     struct toto *res = malloc(sizeof *res);
>>>>     if (res != NULL) memcpy(res, &s, sizeof s);
>>>
>>> Why memcpy instead of an assignment?
>>>       if (res != NULL) *res = s;
>>
>> Because they amount to the same thing, behind the scenes, on a few
>> implementations? ;)  Lots of people still do:
>>
>>     struct tag s;
>>     memset(&s, 0, sizeof s);
>>
>> instead of:
>>
>>     struct tag s = { 0 };
>>
>> But the latter seems better (when possible).
>>
>>>>     return res;
>>>> }
>>>
>>> And how about returning by value?
>>>
>>>     struct toto foo(int i, float f, void *p)
>>>     {
>>>       struct toto res = {i, f, p};
>>>       return res;
>>>     }
>>>
>>
>> This has the same problem with the initializer list, though.
>>
>> I would guess that 'malloc' was being used for lifetime considerations,
>> but obviously only Noob knows.
>
> As I often do, my simplification went a bit too far, so I'll just
> describe the actual use-case.
> (This involves two threads on a POSIX-compliant platform.)
>
> I have a foo_start function which malloc's space for a "context"
> struct, populates the struct according to the function's parameters,
> then spawns a new thread which is passed this context. (This is why
> dynamic allocation must be used.)
>
> To make matters more complex, I have a flexible array at the end of
> the struct.
>
> Basically, struct ctx is defined this way:
>
> struct ctx {
>    int file_idx;
>    const char *buf;
>    sem_t sem;
>    char path[];
> };
>
> void *foo_run(void *arg) {
>    struct ctx *ctx = arg;
>    do stuff in an infinite loop, according to ctx
> }
>
> void foo_start(int param1, int param2, ...)
> {
>    struct ctx *ctx = malloc(sizeof *ctx + paramx);
>    populate the fields of ctx;
>    spawn(foo_run, ctx);
> }
>
> In my current version, I don't have any const qualifiers in my code.
> I like to look at the assembly code generated by the compiler, and I
> noticed that every time I need some field from ctx, the compiler has
> to reload it, instead of caching the value in a register.
>
> As far as I understand, this is expected: the address of the struct
> could be stored anywhere, and any function in a different translation
> unit could "pull the rug" from under me. Except that *I* wrote the
> code, and I *know* (by design) that most fields in the struct do NOT
> change after init.
>
> So I set out to sprinkle a few "const" qualifiers here and there, to
> see if that would convince the compiler that some optimizations are
> indeed possible (I know this looks like a clear case of premature
> optimization, but I figured I might as well learn something new along
> the way!)
>
> I don't think I can just const-qualify the entire struct, because
> 1) the prototype for a thread's entry point is imposed by POSIX
> 2) const-qualifying a pointer parameter is only a contract between
> the user and the function's implementer, saying "my function won't
> touch your preciousss struct", it doesn't say that the struct won't
> be changed by something else.
>
> Whereas, I was under the impression that a const-qualified field
> means "hear, hear, this field SHALL NEVER change!"
>
> Anyway, I'd be happy to hear the word from the regs, and/or take
> this to comp.unix.programmer at some point (although I do believe
> that the core of my question is a C question, not POSIX).
>

Although I gave the wrong answer about C >= C99 aggregate/union 
initializer-list, if you'll still permit, I'd like to offer some 
thoughts on why using 'offsetof' (as a previous post did) might have 
benefit:

   1. Your non-constant initializers require C >= C99.

   2. The work of initialization and then copying to allocated storage 
is more work (but prettier, perhaps) than assigning directly to the 
allocated storage, unless working with automatic objects has a special 
advantage in terms of speed.

   3. For C >= C99, the effective types for the sub-objects in the 
allocated storage will remain modifiable, but the 'struct toto *' used 
to access any of those will only allow 'const' access; perhaps the 
artificial limitation you desire?  "Internal" functions could use 
'offsetof', if needed.

Using 'memcpy' from another 'struct toto' establishes the effective type 
of the allocated storage and then it can be argued that there are 
complications from pointing into the storage with a pointer to an 
unqualified referenced type, then using such pointers to read the value. 
  (Although I think that argument would disappear if you use a 'const 
int *' to read the 'const int' sub-object of the allocated storage, 
instead.)

-- 
- Shao Miller
--
"Thank you for the kind words; those are the kind of words I like to hear.

Cheerily,"  -- Richard Harter

[toc] | [prev] | [next] | [standalone]


Page 1 of 4  [1] 2 3 4  Next page →

Back to top | Article view | comp.lang.c


csiph-web