Velocity Reviews - Computer Hardware Reviews

Velocity Reviews > Newsgroups > Programming > C Programming > Initializing a malloc'ed struct whose fields are const with run-timevalues

Reply
Thread Tools

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

 
 
Shao Miller
Guest
Posts: n/a
 
      01-23-2013
On 1/22/2013 23:28, Ben Bacarisse wrote:
> Shao Miller <(E-Mail Removed)> writes:
>
>> On 1/22/2013 17:37, Ben Bacarisse wrote:
>>> Shao Miller <(E-Mail Removed)> writes:
>>>
>>>> On 1/22/2013 16:02, Ben Bacarisse wrote:
>>>>> Ike Naar <(E-Mail Removed)> writes:
>>>>>
>>>>>> On 2013-01-22, Noob <root@127.0.0.1> wrote:
>>>
>>> <snipping has lost the fact that struct toto has const qualified members>
>>>
>>>>>> And how about returning by value?
>>>>>>
>>>>>> struct toto foo(int i, float f, void *p)
>>>>>> {
>>>>>> struct toto res = {i, f, p};
>>>>>> return res;
>>>>>> }
>>>>>
>>>>> This limits what you can do with it for the same reason. You can't
>>>>> assign a strust toto because of its const members.
>>>>
>>>> Are you sure about that? 'res' undergoes lvalue conversion and no
>>>> longer has qualified type.
>>>
>>> Am I sure about what? I think you know that you can't assign to a
>>> struct toto object, so are you saying if I am sure that returning this
>>> struct type limits what one can do with it?
>>>
>>> A pointer to allocated storage is more flexible (because you have
>>> control over the lifetime) and the function as given is almost identical
>>> to a simple expression: (struct toto){i, f, p}.
>>>

>>
>> Sorry, Ben. I've approached this in my head in four ways:
>>
>> 1. (Non-preferred; must be wrong because of lvalue conversion)
>>
>> 'res', before lvalue conversion, has a compatible type with the return
>> type of the function, so "the value is converted as if by assignment
>> to an object having the return type of the function" does not apply,
>> and "the value of" 'res' "is returned to the caller as the value of
>> the function call expression"
>>
>> 2. (More preferred than #1)
>>
>> 'res' undergoes lvalue conversion and yields an unqualified type with
>> the value. This type is incompatible with the return type of the
>> function, so "the value is converted as if by assignment to an object
>> having the return type of the function", but the footnote reminds us
>> that "The return statement is not an assignment." So there might be
>> one or more differences.
>>
>> Looking at 6.5.16p1, it cannot apply as it is, since "an object having
>> the return type of the function" isn't the same as "a modifiable
>> lvalue designating an object having the return type of the function."
>> We need to twist it a bit. There's also no direct discussion of
>> conversion for the RHS operand... That's "2 strikes". So what if we
>> drop that bit and move on to 6.5.16.1?
>>
>> Alternatively to moving on, there's a constraint violation (as you've
>> mentioned) based on "modifiable". But why pick "modifiable" and not
>> "lvalue"?
>>
>> Looking at 6.5.16.1p1, the return type of 'foo' and the unqualified
>> type of rvalue from 'res' satisfy the second bullet. Then p2 does
>> indeed refer back to 6.5.16p2, but only insofar as the type of the
>> assignment-expression. The type of the assignment-expression so
>> happens to be the unqualified type of 'struct toto', which is the same
>> type as the rvalue from 'res', so there's actually no conversion for
>> the rvalue from 'res'.
>>
>> 3. (Preferred)
>>
>> 6.7.3p4: "The properties associated with qualified types are
>> meaningful only for expressions that are lvalues.132)" But "the value
>> of the function call expression" is never an lvalue, so perhaps the
>> return type of a function is never qualified.
>>
>> In that case, the lvalue conversion of 'res' yields an rvalue whose
>> type is already compatible with the return type, so "the value is
>> converted as if by assignment to an object having the return type of
>> the function" does not apply, and "the value of" 'res' "is returned to
>> the caller as the value of the function call expression".
>>
>> If #3 is true, the wording could be a bit clearer.
>>
>> 4. (D'oh!)
>>
>> Unfortunately, I don't think any of #1, #2, #3 is true, due to
>> 6.7.3p9: "...If the specification of a function type includes any type
>> qualifiers, the behavior is undefined.136)" (Since at least C90.) I
>> think that means that 'foo' can't be declared that way.

>
> You wrote eight paragraphs of stuff that you don't think is true?
>


Well I was hopeful for #3, but seemed to recall having previously read
some other bit of Standard text contradicting it. When I went looking,
I came across 6.7.3p9 and it looked like it was the antagonist. Perhaps
that wasn't it, after all.

> How do you interpret 6.7.3 p9 so that the function above is undefined,
> but const char *int_to_str(int) is not?
>
>> (This is Ike Naar's 'foo', obviously. Citations relative to N1570.)

>


Well I was thinking along the lines of the qualification of the return
type's type category, but maybe not...

Have you any thoughts about #1, #2, #3?

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

Cheerily," -- Richard Harter
 
Reply With Quote
 
 
 
 
Tim Rentsch
Guest
Posts: n/a
 
      01-23-2013
James Kuyper <(E-Mail Removed)> writes:

> On 01/22/2013 04:19 PM, William Ahern wrote:
>> Ian Collins <(E-Mail Removed)> wrote:

> ...
>>> Is that legal? struct toto has const members, so can it be returned by
>>> value from a function?

>>
>> What about foo().f? Does the simple return constitute modification of a
>> const-qualified lvalue?
>>
>> I'm still not convinced that "modifying" a const-qualified member through
>> assignment of a non-const-qualified aggregate is undefined behaviour. But I
>> don't know enough about the rules of lvalues to prove it.

>
> A struct containing a member that is const-qualified is not modifiable
> (6.3.2.1p1). It is a constraint violation for an assignment operator to
> have a left operand which is not a modifiable lvalue (6.5.16p2).
> Arguments passed to a function (6.5.2.2p7), and values returned by a
> function (6.8.6.4p3), are both converted "as if by assignment", and I
> believe are therefore subject to the same constraints.


Too funny.

First, the constraint violation for assignment operators has
nothing to do with conversions that are done as part of performing
the operation. These aspects appear in different paragraphs and
in different types of subsections.

Second, 'return' only does such an assignment-like conversion
when the type of the return expression differs from the result
type of the function.
 
Reply With Quote
 
 
 
 
Tim Rentsch
Guest
Posts: n/a
 
      01-23-2013
Ian Collins <(E-Mail Removed)> writes:

>> [snip]
>>

> I just tried this code:
>
> #include <stdio.h>
>
> struct toto { const int i; const float f; const void *p; };
>
> struct toto foo(int i, float f, void *p)
> {
> return (struct toto){i, f, p};
> }
>
> int main(void)
> {
> float f = foo( 1,2,NULL).f;
> }
>
> and gcc (-Wall -std=c99 -pedantic) compiles it, but Sun c99 (which
> tends to be both strict and conforming) rejects it with one error:
>
> "x.c", line 7: left operand must be modifiable lvalue: op "="
>
> where line 7 is the function return.


I believe gcc has it right here. Even the error message from
the Sun compiler suggests they were thinking of this like a
kind of assignment, which it certainly isn't in this case.
 
Reply With Quote
 
Ian Collins
Guest
Posts: n/a
 
      01-23-2013
Tim Rentsch wrote:
> Ian Collins <(E-Mail Removed)> writes:
>
>> Ike Naar wrote:
>>>> [snip]
>>>
>>> And how about returning by value?
>>>
>>> struct toto foo(int i, float f, void *p)
>>> {
>>> struct toto res = {i, f, p};
>>> return res;
>>> }

>>
>> Is that legal? struct toto has const members, so can it be
>> returned by value from a function?

>
> Can you name a constraint or a 'shall' provision that it
> violates? I can't find one. If there is no such violation,
> then the behavior is well-defined (and I believe that is in
> fact the case).


No, I'm not one for remembering where stuff is in the standard... But I
think I (and possibly the Sun compiler writers) took the assignment like
nature of return too literally.

--
Ian Collins
 
Reply With Quote
 
Tim Rentsch
Guest
Posts: n/a
 
      01-23-2013
Ian Collins <(E-Mail Removed)> writes:

> Tim Rentsch wrote:
>> Ian Collins <(E-Mail Removed)> writes:
>>
>>> Ike Naar wrote:
>>>>> [snip]
>>>>
>>>> And how about returning by value?
>>>>
>>>> struct toto foo(int i, float f, void *p)
>>>> {
>>>> struct toto res = {i, f, p};
>>>> return res;
>>>> }
>>>
>>> Is that legal? struct toto has const members, so can it be
>>> returned by value from a function?

>>
>> Can you name a constraint or a 'shall' provision that it
>> violates? I can't find one. If there is no such violation,
>> then the behavior is well-defined (and I believe that is in
>> fact the case).

>
> No, I'm not one for remembering where stuff is in the
> standard...


Sorry, what I said came out sounding accusatory and I
didn't mean it that way. All I meant was, this question
is what should be considered to resolve the issue.

> But I think I (and possibly the Sun compiler writers) took
> the assignment like nature of return too literally.


Actually my first reaction was similar to that, even though
I wasn't thinking specifically of assignment. Upon further
consideration though allowing it makes more sense, because
what's happening is more like an initialization than an
assignment, and initializers certainly are allowed for
const-qualified types.
 
Reply With Quote
 
Ian Collins
Guest
Posts: n/a
 
      01-23-2013
Tim Rentsch wrote:
> Ian Collins <(E-Mail Removed)> writes:
>
>> Tim Rentsch wrote:
>>> Ian Collins <(E-Mail Removed)> writes:
>>>
>>>> Ike Naar wrote:
>>>>>> [snip]
>>>>>
>>>>> And how about returning by value?
>>>>>
>>>>> struct toto foo(int i, float f, void *p)
>>>>> {
>>>>> struct toto res = {i, f, p};
>>>>> return res;
>>>>> }
>>>>
>>>> Is that legal? struct toto has const members, so can it be
>>>> returned by value from a function?
>>>
>>> Can you name a constraint or a 'shall' provision that it
>>> violates? I can't find one. If there is no such violation,
>>> then the behavior is well-defined (and I believe that is in
>>> fact the case).

>>
>> No, I'm not one for remembering where stuff is in the
>> standard...

>
> Sorry, what I said came out sounding accusatory and I
> didn't mean it that way. All I meant was, this question
> is what should be considered to resolve the issue.


No offense taken.

>> But I think I (and possibly the Sun compiler writers) took
>> the assignment like nature of return too literally.

>
> Actually my first reaction was similar to that, even though
> I wasn't thinking specifically of assignment. Upon further
> consideration though allowing it makes more sense, because
> what's happening is more like an initialization than an
> assignment, and initializers certainly are allowed for
> const-qualified types.


Now I've taken the time to check 6.8.6.4p3 I think the wording

"the value of the expression is returned to the caller as the value of
the function call expression"

is clear enough. I might ask the now Oracle compiler people why they
consider it an error.

--
Ian Collins
 
Reply With Quote
 
Ben Bacarisse
Guest
Posts: n/a
 
      01-23-2013
Shao Miller <(E-Mail Removed)> 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.
 
Reply With Quote
 
Noob
Guest
Posts: n/a
 
      01-23-2013
Ben Bacarisse wrote:

> Shao Miller <(E-Mail Removed)> 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.

 
Reply With Quote
 
BartC
Guest
Posts: n/a
 
      01-23-2013


"Noob" <root@127.0.0.1> wrote in message news:kdonp9$lqb$(E-Mail Removed)...

> 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


 
Reply With Quote
 
Ben Bacarisse
Guest
Posts: n/a
 
      01-23-2013
Tim Rentsch <(E-Mail Removed)> writes:

> Ian Collins <(E-Mail Removed)> writes:
>
>>> [snip]
>>>

>> I just tried this code:
>>
>> #include <stdio.h>
>>
>> struct toto { const int i; const float f; const void *p; };
>>
>> struct toto foo(int i, float f, void *p)
>> {
>> return (struct toto){i, f, p};
>> }
>>
>> int main(void)
>> {
>> float f = foo( 1,2,NULL).f;
>> }
>>
>> and gcc (-Wall -std=c99 -pedantic) compiles it, but Sun c99 (which
>> tends to be both strict and conforming) rejects it with one error:
>>
>> "x.c", line 7: left operand must be modifiable lvalue: op "="
>>
>> where line 7 is the function return.

>
> I believe gcc has it right here. Even the error message from
> the Sun compiler suggests they were thinking of this like a
> kind of assignment, which it certainly isn't in this case.


As you say elsewhere, the assignment-like nature of the return only
kicks in when the types differ, but even when it does, I'd take "is
converted as if by assignment" to mean that only the conversion and type
constraints of assignment are to be considered. (The constraints being
important because they would, for example, prevent a function with type
'T *' returning a 'const T * value without a diagnostic).

More curious to me is that gcc (in conforming mode) permits this:

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

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

int bar(struct toto p) { return p.i; }

int main(void)
{
return bar(foo(1, 2, 0));
}

but 6.5.2.2 p2 says:

"Each argument shall have a type such that its value may be assigned
to an object with the unqualified version of the type of its
corresponding parameter."

The phrase "unqualified version of the type" can't surely be intended to
mean the recursive removal of all type qualifiers. Elsewhere it simply
means that the "top level" qualifiers are removed. If that's the right
interpretation, the call to bar should be a constraint violation.

It looks like gcc is borrowing from C++ where argument passing is
defined to like initialisation (which I've always found that to be more
logical than C's assignment-like call semantics). Anyway, either I'm
misreading something or gcc has missed something.

--
Ben.
 
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
Can *common* struct-members of 2 different struct-types, that are thesame for the first common members, be accessed via pointer cast to either struct-type? John Reye C Programming 28 05-08-2012 12:24 AM
print struct fields and its member structs' fields recursively, generically call_me_anything C++ 4 09-30-2007 10:12 PM
const vector<A> vs vector<const A> vs const vector<const A> Javier C++ 2 09-04-2007 08:46 PM
Casting int'** to 'const int * const * const' dosn't work, why? Jonas.Holmsten@gmail.com C Programming 11 07-01-2007 06:16 PM
struct my_struct *p = (struct my_struct *)malloc(sizeof(struct my_struct)); Chris Fogelklou C Programming 36 04-20-2004 08:27 AM



Advertisments