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

 
 
Ben Bacarisse
Guest
Posts: n/a
 
      01-23-2013
Shao Miller <> writes:

> On 1/22/2013 23:28, Ben Bacarisse wrote:
>> Shao Miller <> writes:
>>
>>> On 1/22/2013 17:37, Ben Bacarisse wrote:
>>>> Shao Miller <> writes:
>>>>
>>>>> On 1/22/2013 16:02, Ben Bacarisse wrote:
>>>>>> Ike Naar <> 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...


I don't know what a type's type category is so I can't comment here.

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


The return type is the same as that of the function so no conversion
takes place. The value of res is the value returned. It does not seem
to be complicated to me.

--
Ben.
 
Reply With Quote
 
 
 
 
Noob
Guest
Posts: n/a
 
      01-23-2013
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.

 
Reply With Quote
 
 
 
 
Ben Bacarisse
Guest
Posts: n/a
 
      01-23-2013
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.
 
Reply With Quote
 
Noob
Guest
Posts: n/a
 
      01-23-2013
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.

 
Reply With Quote
 
Ben Bacarisse
Guest
Posts: n/a
 
      01-23-2013
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.
 
Reply With Quote
 
Shao Miller
Guest
Posts: n/a
 
      01-23-2013
On 1/23/2013 08:54, Ben Bacarisse wrote:
> Tim Rentsch <> writes:
>
>> Ian Collins <ian-> 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.
>


Why? The result of the call to 'foo' yields a 'struct toto', which is
not qualified (and also isn't an lvalue).

> 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.
>


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

Cheerily," -- Richard Harter
 
Reply With Quote
 
Shao Miller
Guest
Posts: n/a
 
      01-23-2013
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
 
Reply With Quote
 
Ian Collins
Guest
Posts: n/a
 
      01-23-2013
Shao Miller wrote:
> On 1/23/2013 08:54, Ben Bacarisse wrote:
>> Tim Rentsch <> writes:
>>
>>> Ian Collins <ian-> 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.
>>

>
> Why? The result of the call to 'foo' yields a 'struct toto', which is
> not qualified (and also isn't an lvalue).


I think Ben's point is the *parameter* value may be *assigned*, not the
result of the expression.

I see Sun c99, which rejects the return in foo, also accepts bar.

--
Ian Collins
 
Reply With Quote
 
Shao Miller
Guest
Posts: n/a
 
      01-23-2013
On 1/23/2013 17:29, Ian Collins wrote:
> Shao Miller wrote:
>> On 1/23/2013 08:54, Ben Bacarisse wrote:
>>> Tim Rentsch <> writes:
>>>
>>>> Ian Collins <ian-> 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.
>>>

>>
>> Why? The result of the call to 'foo' yields a 'struct toto', which is
>> not qualified (and also isn't an lvalue).

>
> I think Ben's point is the *parameter* value may be *assigned*, not the
> result of the expression.
>
> I see Sun c99, which rejects the return in foo, also accepts bar.
>


As in, a constraint violation against 6.5.16p2? If so, why would that
constraint apply? There are still constraints in 6.5.16.1p1... As
asked elsethread, why pick out "modifiable" and not "lvalue"? Do we
need to worry about the constraints and semantics of 6.5.16.2? Isn't
backing up to 6.5.16 backing up too far?

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

Cheerily," -- Richard Harter
 
Reply With Quote
 
Ben Bacarisse
Guest
Posts: n/a
 
      01-23-2013
Ian Collins <ian-> writes:

> Shao Miller wrote:
>> On 1/23/2013 08:54, Ben Bacarisse wrote:
>>> Tim Rentsch <> writes:
>>>
>>>> Ian Collins <ian-> 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.
>>>

>>
>> Why? The result of the call to 'foo' yields a 'struct toto', which is
>> not qualified (and also isn't an lvalue).

>
> I think Ben's point is the *parameter* value may be *assigned*, not
> the result of the expression.


Yes, the types are fine but a value of stuct foo type can't be assigned
to an object of that type. It reads as though parameter passing is,
essentially, assignment and whilst you can initialise a struct toto
object, you can't assign to one.

[I've just snipped a long and tedious paragraph trying to give some other
meaning to the phrasing, but since I don't buy it seems pointless to punt
it.]

> I see Sun c99, which rejects the return in foo, also accepts bar.


Interesting. Is it also a C++ compiler when given other options? C++
uses initialisation semantics for parameter passing, so it might be an
accident. Of course it could just be that the gcc and Sun c99 authors
are just better as reading standards!

--
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
 



1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57