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


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

Array is an non-modifiable lvalue - where does it matter?

Started byAndrey Tarasevich <andreytarasevich@hotmail.com>
First post2021-07-15 13:21 -0700
Last post2021-07-23 23:26 -0700
Articles 20 on this page of 28 — 9 participants

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


Contents

  Array is an non-modifiable lvalue - where does it matter? Andrey Tarasevich <andreytarasevich@hotmail.com> - 2021-07-15 13:21 -0700
    Re: Array is an non-modifiable lvalue - where does it matter? Öö Tiib <ootiib@hot.ee> - 2021-07-15 13:55 -0700
      Re: Array is an non-modifiable lvalue - where does it matter? Ben Bacarisse <ben.usenet@bsb.me.uk> - 2021-07-15 22:12 +0100
        Re: Array is an non-modifiable lvalue - where does it matter? Öö Tiib <ootiib@hot.ee> - 2021-07-15 15:07 -0700
          Re: Array is an non-modifiable lvalue - where does it matter? David Brown <david.brown@hesbynett.no> - 2021-07-16 09:52 +0200
            Re: Array is an non-modifiable lvalue - where does it matter? Keith Thompson <Keith.S.Thompson+u@gmail.com> - 2021-07-16 02:31 -0700
            Re: Array is an non-modifiable lvalue - where does it matter? Andrey Tarasevich <andreytarasevich@hotmail.com> - 2021-07-16 10:59 -0700
              Re: Array is an non-modifiable lvalue - where does it matter? David Brown <david.brown@hesbynett.no> - 2021-07-17 16:23 +0200
                Re: Array is an non-modifiable lvalue - where does it matter? James Kuyper <jameskuyper@alumni.caltech.edu> - 2021-07-17 20:14 -0400
      Re: Array is an non-modifiable lvalue - where does it matter? Andrey Tarasevich <andreytarasevich@hotmail.com> - 2021-07-15 14:36 -0700
        Re: Array is an non-modifiable lvalue - where does it matter? Öö Tiib <ootiib@hot.ee> - 2021-07-15 15:19 -0700
    Re: Array is an non-modifiable lvalue - where does it matter? Keith Thompson <Keith.S.Thompson+u@gmail.com> - 2021-07-15 14:06 -0700
    Re: Array is an non-modifiable lvalue - where does it matter? James Kuyper <jameskuyper@alumni.caltech.edu> - 2021-07-16 14:22 -0400
      Re: Array is an non-modifiable lvalue - where does it matter? Andrey Tarasevich <andreytarasevich@hotmail.com> - 2021-07-16 11:43 -0700
        Re: Array is an non-modifiable lvalue - where does it matter? Andrey Tarasevich <andreytarasevich@hotmail.com> - 2021-07-17 18:24 -0700
          Re: Array is an non-modifiable lvalue - where does it matter? Keith Thompson <Keith.S.Thompson+u@gmail.com> - 2021-07-17 20:29 -0700
          Re: Array is an non-modifiable lvalue - where does it matter? Siri Cruise <chine.bleu@yahoo.com> - 2021-07-17 21:25 -0700
      Re: Array is an non-modifiable lvalue - where does it matter? Keith Thompson <Keith.S.Thompson+u@gmail.com> - 2021-07-16 15:22 -0700
    Re: Array is an non-modifiable lvalue - where does it matter? Kaz Kylheku <563-365-8930@kylheku.com> - 2021-07-16 22:21 +0000
      Re: Array is an non-modifiable lvalue - where does it matter? Andrey Tarasevich <andreytarasevich@hotmail.com> - 2021-07-16 23:27 -0700
        Re: Array is an non-modifiable lvalue - where does it matter? Kaz Kylheku <563-365-8930@kylheku.com> - 2021-07-17 16:53 +0000
          Re: Array is an non-modifiable lvalue - where does it matter? Andrey Tarasevich <andreytarasevich@hotmail.com> - 2021-07-17 10:49 -0700
          Re: Array is an non-modifiable lvalue - where does it matter? Keith Thompson <Keith.S.Thompson+u@gmail.com> - 2021-07-17 14:01 -0700
        Re: Array is an non-modifiable lvalue - where does it matter? Ben Bacarisse <ben.usenet@bsb.me.uk> - 2021-07-18 02:09 +0100
      Re: Array is an non-modifiable lvalue - where does it matter? James Kuyper <jameskuyper@alumni.caltech.edu> - 2021-07-17 20:12 -0400
    Re: Array is an non-modifiable lvalue - where does it matter? "Chris M. Thomasson" <chris.m.thomasson.1@gmail.com> - 2021-07-17 13:20 -0700
      Re: Array is an non-modifiable lvalue - where does it matter? Andrey Tarasevich <andreytarasevich@hotmail.com> - 2021-07-19 14:44 -0700
        Re: Array is an non-modifiable lvalue - where does it matter? "Chris M. Thomasson" <chris.m.thomasson.1@gmail.com> - 2021-07-23 23:26 -0700

Page 1 of 2  [1] 2  Next page →


#161918 — Array is an non-modifiable lvalue - where does it matter?

FromAndrey Tarasevich <andreytarasevich@hotmail.com>
Date2021-07-15 13:21 -0700
SubjectArray is an non-modifiable lvalue - where does it matter?
Message-ID<scq5c5$tql$1@dont-email.me>
6.3.2/1 says that

   1 [...] A modifiable lvalue is an lvalue that does not have array 
type, [...]

Based on that, arrays are non-modifiable lvalues. We all know what it 
actually means. But is there any context in the standard in which this 
non-modifiability of array lvalues would actually _matter_, would 
actually interact with some other standard requirement?

One thing that comes to mind is a constraint on assignment operators 
(6.5.16/2)

   2 An assignment operator shall have a modifiable lvalue as its left 
operand.

So, one can combine 6.3.2/1 and 6.5.16/2 and conclude that one can't 
assign to arrays. But I believe that constraints are intended/supposed 
to be applied after automatic implicit conversions. And since LHS of 
assignment is not one of the contexts excluded from array type decay, 
said decay is already sufficient to prevent assignment to arrays.

Am I right here? Is the constraint of 6.5.16/2 supposed to be applied 
before automatic implicit conversions or after them?

And if the answer is "after", then is there any other context in C 
standard where non-modifiability of array lvalues would make a difference?

-- 
Best regards,
Andrey Tarasevich

[toc] | [next] | [standalone]


#161919

FromÖö Tiib <ootiib@hot.ee>
Date2021-07-15 13:55 -0700
Message-ID<5c1d96ea-c554-4aa1-b0db-a7729027ee04n@googlegroups.com>
In reply to#161918
On Thursday, 15 July 2021 at 23:21:37 UTC+3, Andrey Tarasevich wrote:
> 6.3.2/1 says that 
> 
> 1 [...] A modifiable lvalue is an lvalue that does not have array 
> type, [...] 
> 
> Based on that, arrays are non-modifiable lvalues. We all know what it 
> actually means. But is there any context in the standard in which this 
> non-modifiability of array lvalues would actually _matter_, would 
> actually interact with some other standard requirement? 
> 
> One thing that comes to mind is a constraint on assignment operators 
> (6.5.16/2) 
> 
> 2 An assignment operator shall have a modifiable lvalue as its left 
> operand. 
> 
> So, one can combine 6.3.2/1 and 6.5.16/2 and conclude that one can't 
> assign to arrays. But I believe that constraints are intended/supposed 
> to be applied after automatic implicit conversions. And since LHS of 
> assignment is not one of the contexts excluded from array type decay, 
> said decay is already sufficient to prevent assignment to arrays. 
> 
> Am I right here? Is the constraint of 6.5.16/2 supposed to be applied 
> before automatic implicit conversions or after them? 
> 
> And if the answer is "after", then is there any other context in C 
> standard where non-modifiability of array lvalues would make a difference? 

It is so that we can't modify address of array so
rest of operators that can modify lvalue like ++ or += also
will be rejected on case of an array. But I might misunderstand
what you are asking.

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


#161921

FromBen Bacarisse <ben.usenet@bsb.me.uk>
Date2021-07-15 22:12 +0100
Message-ID<875yxbth6r.fsf@bsb.me.uk>
In reply to#161919
Öö Tiib <ootiib@hot.ee> writes:

> On Thursday, 15 July 2021 at 23:21:37 UTC+3, Andrey Tarasevich wrote:
>> 6.3.2/1 says that 
>> 
>> 1 [...] A modifiable lvalue is an lvalue that does not have array 
>> type, [...] 
>> 
>> Based on that, arrays are non-modifiable lvalues. We all know what it 
>> actually means. But is there any context in the standard in which this 
>> non-modifiability of array lvalues would actually _matter_, would 
>> actually interact with some other standard requirement? 
>> 
>> One thing that comes to mind is a constraint on assignment operators 
>> (6.5.16/2) 
>> 
>> 2 An assignment operator shall have a modifiable lvalue as its left 
>> operand. 
>> 
>> So, one can combine 6.3.2/1 and 6.5.16/2 and conclude that one can't 
>> assign to arrays. But I believe that constraints are intended/supposed 
>> to be applied after automatic implicit conversions. And since LHS of 
>> assignment is not one of the contexts excluded from array type decay, 
>> said decay is already sufficient to prevent assignment to arrays. 
>> 
>> Am I right here? Is the constraint of 6.5.16/2 supposed to be applied 
>> before automatic implicit conversions or after them? 
>> 
>> And if the answer is "after", then is there any other context in C 
>> standard where non-modifiability of array lvalues would make a difference? 
>
> It is so that we can't modify address of array so
> rest of operators that can modify lvalue like ++ or += also
> will be rejected on case of an array. But I might misunderstand
> what you are asking.

Yes, you've missed the point of the question.  Lvalue expressions of
array type are, in almost all situations, converted to pointers to the
first element of the array, and *the result is no longer an lvalue*.
(The exceptions are the operands of &, sizeof and _Alignof and when a
string literal is used to initialise an array.)

Thus, given `int a[1]`, the expression `a++` is invalid because the
operand is not an lvalue at all.

Andrey is asking whether there are any situations where it matters that
the standard excludes array-valued lvalues from being modifiable
lvalues.  Could that wording simply have been left out or would that
permit something, not excluded by other wording, from being valid C?

I *think* the answer is yes -- there would be no harm (other than maybe
a loss of clarity) in removing that wording.  But I had deliberately not
answered because this is the sort of question that requires a more
thorough knowledge of the standard than I possess to answer with any
confidence.

-- 
Ben.

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


#161923

FromÖö Tiib <ootiib@hot.ee>
Date2021-07-15 15:07 -0700
Message-ID<e6132d4c-d915-492a-a76e-2d4a2062d353n@googlegroups.com>
In reply to#161921
On Friday, 16 July 2021 at 00:12:40 UTC+3, Ben Bacarisse wrote:
>  Öö Tiib <oot...@hot.ee> writes: 
> 
> > On Thursday, 15 July 2021 at 23:21:37 UTC+3, Andrey Tarasevich wrote: 
> >> 6.3.2/1 says that 
> >> 
> >> 1 [...] A modifiable lvalue is an lvalue that does not have array 
> >> type, [...] 
> >> 
> >> Based on that, arrays are non-modifiable lvalues. We all know what it 
> >> actually means. But is there any context in the standard in which this 
> >> non-modifiability of array lvalues would actually _matter_, would 
> >> actually interact with some other standard requirement? 
> >> 
> >> One thing that comes to mind is a constraint on assignment operators 
> >> (6.5.16/2) 
> >> 
> >> 2 An assignment operator shall have a modifiable lvalue as its left 
> >> operand. 
> >> 
> >> So, one can combine 6.3.2/1 and 6.5.16/2 and conclude that one can't 
> >> assign to arrays. But I believe that constraints are intended/supposed 
> >> to be applied after automatic implicit conversions. And since LHS of 
> >> assignment is not one of the contexts excluded from array type decay, 
> >> said decay is already sufficient to prevent assignment to arrays. 
> >> 
> >> Am I right here? Is the constraint of 6.5.16/2 supposed to be applied 
> >> before automatic implicit conversions or after them? 
> >> 
> >> And if the answer is "after", then is there any other context in C 
> >> standard where non-modifiability of array lvalues would make a difference? 
> > 
> > It is so that we can't modify address of array so 
> > rest of operators that can modify lvalue like ++ or += also 
> > will be rejected on case of an array. But I might misunderstand 
> > what you are asking.
> 
> Yes, you've missed the point of the question. Lvalue expressions of 
> array type are, in almost all situations, converted to pointers to the 
> first element of the array, and *the result is no longer an lvalue*. 
> (The exceptions are the operands of &, sizeof and _Alignof and when a 
> string literal is used to initialise an array.) 
> 
> Thus, given `int a[1]`, the expression `a++` is invalid because the 
> operand is not an lvalue at all. 

Yes and so a = b is invalid because a turns into something that is
not lvalue at all. But saying that it is not modifiable does not hurt?
 
> Andrey is asking whether there are any situations where it matters that 
> the standard excludes array-valued lvalues from being modifiable 
> lvalues. Could that wording simply have been left out or would that 
> permit something, not excluded by other wording, from being valid C? 
> 
> I *think* the answer is yes -- there would be no harm (other than maybe 
> a loss of clarity) in removing that wording. But I had deliberately not 
> answered because this is the sort of question that requires a more 
> thorough knowledge of the standard than I possess to answer with any 
> confidence. 

Thanks for clarifying. I don't think that it is bad when standard repeats
something over even if it is deducible from other parts. Especially
about arrays that seem to be constant source of confusion among 
people who try to learn C.

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


#161925

FromDavid Brown <david.brown@hesbynett.no>
Date2021-07-16 09:52 +0200
Message-ID<scrdrf$g4r$1@dont-email.me>
In reply to#161923
On 16/07/2021 00:07, Öö Tiib wrote:
> On Friday, 16 July 2021 at 00:12:40 UTC+3, Ben Bacarisse wrote:
>>  Öö Tiib <oot...@hot.ee> writes: 
>>
>>> On Thursday, 15 July 2021 at 23:21:37 UTC+3, Andrey Tarasevich wrote: 
>>>> 6.3.2/1 says that 
>>>>
>>>> 1 [...] A modifiable lvalue is an lvalue that does not have array 
>>>> type, [...] 
>>>>
>>>> Based on that, arrays are non-modifiable lvalues. We all know what it 
>>>> actually means. But is there any context in the standard in which this 
>>>> non-modifiability of array lvalues would actually _matter_, would 
>>>> actually interact with some other standard requirement? 
>>>>
>>>> One thing that comes to mind is a constraint on assignment operators 
>>>> (6.5.16/2) 
>>>>
>>>> 2 An assignment operator shall have a modifiable lvalue as its left 
>>>> operand. 
>>>>
>>>> So, one can combine 6.3.2/1 and 6.5.16/2 and conclude that one can't 
>>>> assign to arrays. But I believe that constraints are intended/supposed 
>>>> to be applied after automatic implicit conversions. And since LHS of 
>>>> assignment is not one of the contexts excluded from array type decay, 
>>>> said decay is already sufficient to prevent assignment to arrays. 
>>>>
>>>> Am I right here? Is the constraint of 6.5.16/2 supposed to be applied 
>>>> before automatic implicit conversions or after them? 
>>>>
>>>> And if the answer is "after", then is there any other context in C 
>>>> standard where non-modifiability of array lvalues would make a difference? 
>>>
>>> It is so that we can't modify address of array so 
>>> rest of operators that can modify lvalue like ++ or += also 
>>> will be rejected on case of an array. But I might misunderstand 
>>> what you are asking.
>>
>> Yes, you've missed the point of the question. Lvalue expressions of 
>> array type are, in almost all situations, converted to pointers to the 
>> first element of the array, and *the result is no longer an lvalue*. 
>> (The exceptions are the operands of &, sizeof and _Alignof and when a 
>> string literal is used to initialise an array.) 
>>
>> Thus, given `int a[1]`, the expression `a++` is invalid because the 
>> operand is not an lvalue at all. 
> 
> Yes and so a = b is invalid because a turns into something that is
> not lvalue at all. But saying that it is not modifiable does not hurt?
>  

As far as I can tell (there are others here that are better than I at
interpreting the exact wording of the standards), the wording in the
standard has been misinterpreted here.

The standard says "A modifiable lvalue is an lvalue that does not have
array type".  When applied to "a = b", this has been interpreted to mean
that "a" is an lvalue of array type and therefore a non-modifiable
lvalue, so you cannot use the assignment.  This is, AFAICS, subtly
incorrect - used here, "a" is converted to a non-lvalue pointer to its
first element.  It is not an lvalue at all, modifiable or non-modifiable.

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


#161927

FromKeith Thompson <Keith.S.Thompson+u@gmail.com>
Date2021-07-16 02:31 -0700
Message-ID<87eeby38rd.fsf@nosuchdomain.example.com>
In reply to#161925
David Brown <david.brown@hesbynett.no> writes:
> On 16/07/2021 00:07, Öö Tiib wrote:
>> On Friday, 16 July 2021 at 00:12:40 UTC+3, Ben Bacarisse wrote:
>>>  Öö Tiib <oot...@hot.ee> writes: 
>>>
>>>> On Thursday, 15 July 2021 at 23:21:37 UTC+3, Andrey Tarasevich wrote: 
>>>>> 6.3.2/1 says that 
>>>>>
>>>>> 1 [...] A modifiable lvalue is an lvalue that does not have array 
>>>>> type, [...] 
>>>>>
>>>>> Based on that, arrays are non-modifiable lvalues. We all know what it 
>>>>> actually means. But is there any context in the standard in which this 
>>>>> non-modifiability of array lvalues would actually _matter_, would 
>>>>> actually interact with some other standard requirement? 
>>>>>
>>>>> One thing that comes to mind is a constraint on assignment operators 
>>>>> (6.5.16/2) 
>>>>>
>>>>> 2 An assignment operator shall have a modifiable lvalue as its left 
>>>>> operand. 
>>>>>
>>>>> So, one can combine 6.3.2/1 and 6.5.16/2 and conclude that one can't 
>>>>> assign to arrays. But I believe that constraints are intended/supposed 
>>>>> to be applied after automatic implicit conversions. And since LHS of 
>>>>> assignment is not one of the contexts excluded from array type decay, 
>>>>> said decay is already sufficient to prevent assignment to arrays. 
>>>>>
>>>>> Am I right here? Is the constraint of 6.5.16/2 supposed to be applied 
>>>>> before automatic implicit conversions or after them? 
>>>>>
>>>>> And if the answer is "after", then is there any other context in C 
>>>>> standard where non-modifiability of array lvalues would make a difference? 
>>>>
>>>> It is so that we can't modify address of array so 
>>>> rest of operators that can modify lvalue like ++ or += also 
>>>> will be rejected on case of an array. But I might misunderstand 
>>>> what you are asking.
>>>
>>> Yes, you've missed the point of the question. Lvalue expressions of 
>>> array type are, in almost all situations, converted to pointers to the 
>>> first element of the array, and *the result is no longer an lvalue*. 
>>> (The exceptions are the operands of &, sizeof and _Alignof and when a 
>>> string literal is used to initialise an array.) 
>>>
>>> Thus, given `int a[1]`, the expression `a++` is invalid because the 
>>> operand is not an lvalue at all. 
>> 
>> Yes and so a = b is invalid because a turns into something that is
>> not lvalue at all. But saying that it is not modifiable does not hurt?
>
> As far as I can tell (there are others here that are better than I at
> interpreting the exact wording of the standards), the wording in the
> standard has been misinterpreted here.
> 
> The standard says "A modifiable lvalue is an lvalue that does not have
> array type".  When applied to "a = b", this has been interpreted to mean
> that "a" is an lvalue of array type and therefore a non-modifiable
> lvalue, so you cannot use the assignment.  This is, AFAICS, subtly
> incorrect - used here, "a" is converted to a non-lvalue pointer to its
> first element.  It is not an lvalue at all, modifiable or non-modifiable.

I think that both of the previous posters in this thread, Ben and Öö,
have correctly said essentially the same think you're saying, that `a`
(after the array-to-pointer conversion) is not an lvalue at all.  I'm
not sure that anyone here has misinterpreted it in the way you suggest.

If you write

    int arr[10];
    size_t s = sizeof arr;

then the expression arr in the second line is an lvalue (because it
designates an object and there's no array-to-pointer conversion)
*and* is not a modifiable lvalue (because it's of array type).
If the "does not have array type" wording were dropped, then arr
would be a modifiable lvalue -- but there's no attempt to modify it,
so it doesn't matter.

-- 
Keith Thompson (The_Other_Keith) Keith.S.Thompson+u@gmail.com
Working, but not speaking, for Philips
void Void(void) { Void(); } /* The recursive call of the void */

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


#161937

FromAndrey Tarasevich <andreytarasevich@hotmail.com>
Date2021-07-16 10:59 -0700
Message-ID<scshd7$r7p$1@dont-email.me>
In reply to#161925
On 7/16/2021 12:52 AM, David Brown wrote:
> 
> The standard says "A modifiable lvalue is an lvalue that does not have
> array type".  When applied to "a = b", this has been interpreted to mean
> that "a" is an lvalue of array type and therefore a non-modifiable
> lvalue, so you cannot use the assignment.  This is, AFAICS, subtly
> incorrect - used here, "a" is converted to a non-lvalue pointer to its
> first element.  It is not an lvalue at all, modifiable or non-modifiable.
> 

That's actually part of the question I was asking originally.

You are implicitly insisting that the array-to-pointer conversion should 
be applied first, and only after that the constraints of the assignment 
operator should be checked.

Can you provide a reference to C standard that would indicate that it is 
supposed to be done in that specific order, and not the other way around?

For example, C++ standard is known to use wording like "this (conversion 
| transformation | adjustment) is applied before and further (analysis | 
consideration) is performed" in order to eliminate such ambiguities.

But I don't see anything like that in C standard. One can argue that it 
doesn't matter since the outcome is functionally the same either way. 
But still... the question is intended as a "language-lawyer" one.

-- 
Best regards,
Andrey Tarasevich

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


#161946

FromDavid Brown <david.brown@hesbynett.no>
Date2021-07-17 16:23 +0200
Message-ID<scup4s$498$1@dont-email.me>
In reply to#161937
On 16/07/2021 19:59, Andrey Tarasevich wrote:
> On 7/16/2021 12:52 AM, David Brown wrote:
>>
>> The standard says "A modifiable lvalue is an lvalue that does not have
>> array type".  When applied to "a = b", this has been interpreted to mean
>> that "a" is an lvalue of array type and therefore a non-modifiable
>> lvalue, so you cannot use the assignment.  This is, AFAICS, subtly
>> incorrect - used here, "a" is converted to a non-lvalue pointer to its
>> first element.  It is not an lvalue at all, modifiable or non-modifiable.
>>
> 
> That's actually part of the question I was asking originally.
> 
> You are implicitly insisting that the array-to-pointer conversion should
> be applied first, and only after that the constraints of the assignment
> operator should be checked.
> 

I'm not sure I'd use the word "insisting", but that is correct.

> Can you provide a reference to C standard that would indicate that it is
> supposed to be done in that specific order, and not the other way around?

Assignment is an operator, and thus the left-hand side is an expression.
 6.3.2.1p3 says:

"""
Except when it is the operand of the sizeof operator, or the unary &
operator, or is a string literal used to initalize an array, an
expression that has type "array of type" is converted to an expression
with type "pointer to type" that points to the initial element of the
array object and is not an lvalue.
"""

As for the order in which the conversions are done here, I think these
come from the grammar of the language - subexpressions must be converted
before the operand using them.  I can't conceive of how a language could
do anything else here, but it is given in 6.5p1 anyway.  (Generated code
can do calculations in any order as long as the results are correct.)

> 
> For example, C++ standard is known to use wording like "this (conversion
> | transformation | adjustment) is applied before and further (analysis |
> consideration) is performed" in order to eliminate such ambiguities.
> 

Yes, but that is because in C++ you can have many implicit conversions
and thus the ordering is not clear.

> But I don't see anything like that in C standard. One can argue that it
> doesn't matter since the outcome is functionally the same either way.
> But still... the question is intended as a "language-lawyer" one.
> 

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


#161955

FromJames Kuyper <jameskuyper@alumni.caltech.edu>
Date2021-07-17 20:14 -0400
Message-ID<scvrp8$auf$2@dont-email.me>
In reply to#161946
On 7/17/21 10:23 AM, David Brown wrote:
> On 16/07/2021 19:59, Andrey Tarasevich wrote:
...
>> You are implicitly insisting that the array-to-pointer conversion should
>> be applied first, and only after that the constraints of the assignment
>> operator should be checked.
>>
> 
> I'm not sure I'd use the word "insisting", but that is correct.
> 
>> Can you provide a reference to C standard that would indicate that it is
>> supposed to be done in that specific order, and not the other way around?
> 
> Assignment is an operator, and thus the left-hand side is an expression.
>  6.3.2.1p3 says:
> 
> """
> Except when it is the operand of the sizeof operator, or the unary &
> operator, or is a string literal used to initalize an array, an
> expression that has type "array of type" is converted to an expression
> with type "pointer to type" that points to the initial element of the
> array object and is not an lvalue.
> """
> 
> As for the order in which the conversions are done here, I think these
> come from the grammar of the language - subexpressions must be converted
> before the operand using them.  I can't conceive of how a language could
> do anything else here, but it is given in 6.5p1 anyway.  (Generated code
> can do calculations in any order as long as the results are correct.)

It's not about the order in which any of the operations occur that
matters. It's about whether the constraints apply before or after the
conversions. Constraints are not actions, and the standard is therefore
less specific about how they are sequenced relative to actual activities.

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


#161922

FromAndrey Tarasevich <andreytarasevich@hotmail.com>
Date2021-07-15 14:36 -0700
Message-ID<scq9pd$j11$1@dont-email.me>
In reply to#161919
On 7/15/2021 1:55 PM, Öö Tiib wrote:
> 
> It is so that we can't modify address of array so
> rest of operators that can modify lvalue like ++ or += also
> will be rejected on case of an array. But I might misunderstand
> what you are asking.

Um... I don't see what you are trying to say here. There's no such 
concept in C as "modifying an address of an exiting object". No need to 
block or prevent it, for arrays or for anything else.

-- 
Best regards,
Andrey Tarasevich

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


#161924

FromÖö Tiib <ootiib@hot.ee>
Date2021-07-15 15:19 -0700
Message-ID<bd014848-757b-4a01-80d4-a3be029ff20fn@googlegroups.com>
In reply to#161922
On Friday, 16 July 2021 at 00:36:57 UTC+3, Andrey Tarasevich wrote:
> On 7/15/2021 1:55 PM, Öö Tiib wrote: 
> > 
> > It is so that we can't modify address of array so 
> > rest of operators that can modify lvalue like ++ or += also 
> > will be rejected on case of an array. But I might misunderstand 
> > what you are asking.
> Um... I don't see what you are trying to say here. There's no such 
> concept in C as "modifying an address of an exiting object". No need to 
> block or prevent it, for arrays or for anything else.

Yes, but that does not matter that there are no features or concepts
in C. After figuring that array decays to pointer a novice tries to
modify that pointer sooner or later. Sometimes "successfully" as array
"parameter" is actually a pointer. Being maximally brief about that 
unlucky and confusing feature is bad idea.

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


#161920

FromKeith Thompson <Keith.S.Thompson+u@gmail.com>
Date2021-07-15 14:06 -0700
Message-ID<87im1b2snz.fsf@nosuchdomain.example.com>
In reply to#161918
Andrey Tarasevich <andreytarasevich@hotmail.com> writes:
> 6.3.2/1 says that
>
>   1 [...] A modifiable lvalue is an lvalue that does not have array
>   type, [...]
>
> Based on that, arrays are non-modifiable lvalues. We all know what it
> actually means. But is there any context in the standard in which this 
> non-modifiability of array lvalues would actually _matter_, would
> actually interact with some other standard requirement?
>
> One thing that comes to mind is a constraint on assignment operators
> (6.5.16/2)
>
>   2 An assignment operator shall have a modifiable lvalue as its left
>   operand.
>
> So, one can combine 6.3.2/1 and 6.5.16/2 and conclude that one can't
> assign to arrays. But I believe that constraints are intended/supposed 
> to be applied after automatic implicit conversions. And since LHS of
> assignment is not one of the contexts excluded from array type decay, 
> said decay is already sufficient to prevent assignment to arrays.
>
> Am I right here? Is the constraint of 6.5.16/2 supposed to be applied
> before automatic implicit conversions or after them?
>
> And if the answer is "after", then is there any other context in C
> standard where non-modifiability of array lvalues would make a
> difference?

My first thought is that the statement is redundant (and that's not
necessarily a bad thing).  Other requirements imply that you can't
assign to arrays, but it doesn't hurt to have an explicit statement to
that effect.

The full definition is:

    A *modifiable lvalue* is an lvalue that does not have array
    type, does not have an incomplete type, does not have a const-
    qualified type, and if it is a structure or union, does not have
    any member (including, recursively, any member or element of
    all contained aggregates or unions) with a const- qualified type.

I *think* that dropping the "does not have array type" wouldn't change
anything, but it's probably clearer as it is.

-- 
Keith Thompson (The_Other_Keith) Keith.S.Thompson+u@gmail.com
Working, but not speaking, for Philips
void Void(void) { Void(); } /* The recursive call of the void */

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


#161938

FromJames Kuyper <jameskuyper@alumni.caltech.edu>
Date2021-07-16 14:22 -0400
Message-ID<scsiq3$ens$1@dont-email.me>
In reply to#161918
On 7/15/21 4:21 PM, Andrey Tarasevich wrote:
> 6.3.2/1 says that
> 
>    1 [...] A modifiable lvalue is an lvalue that does not have array 
> type, [...]
> 
> Based on that, arrays are non-modifiable lvalues. We all know what it 
> actually means. But is there any context in the standard in which this 
> non-modifiability of array lvalues would actually _matter_, would 
> actually interact with some other standard requirement?
> 
> One thing that comes to mind is a constraint on assignment operators 
> (6.5.16/2)
> 
>    2 An assignment operator shall have a modifiable lvalue as its left 
> operand.
> 
> So, one can combine 6.3.2/1 and 6.5.16/2 and conclude that one can't 
> assign to arrays. But I believe that constraints are intended/supposed 
> to be applied after automatic implicit conversions. And since LHS of 
> assignment is not one of the contexts excluded from array type decay, 
> said decay is already sufficient to prevent assignment to arrays. 

The Rationale says "the fact that a[i] is a modifiable lvalue while a is
not has puzzled many students of the language. A more precise
description was incorporated in C89 in the hope of combatting this
confusion."

I have a vague memory that this wording is connected to a subtle issue
with functions that return values of struct type, where the struct
contains an array member. But I can't remember what the issue was.

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


#161939

FromAndrey Tarasevich <andreytarasevich@hotmail.com>
Date2021-07-16 11:43 -0700
Message-ID<scsk02$v8i$1@dont-email.me>
In reply to#161938
On 7/16/2021 11:22 AM, James Kuyper wrote:
> 
> I have a vague memory that this wording is connected to a subtle issue
> with functions that return values of struct type, where the struct
> contains an array member. But I can't remember what the issue was.
> 

The issue(s) stem from the combination of the following bits and pieces:

   1. Function return is always an rvalue
   2. Member array of an rvalue struct object is also an rvalue
   3. The result of unary '*' is always an lvalue. And, say, `[]` is 
defined through unary '*' and '+'.

2 and 3 conflict with each other.

C89/90 resolved this problem by stating that array-to-pointer conversion 
is only applicable to lvalue arrays. This basically made rvalue arrays 
inaccessible

   struct S { int a[10]; };

   struct S foo(void)
   {
     struct S s = { 0 };
     return s;
   }

   int main()
   {
     int i = foo().a[0]; /* <- error in C89/90 */
     return 0;
   }

The above code would report a constraint violation: it is not possible 
to apply `[]` to `foo().a`.

C99 decided to change that. Starting from C99 array-to-pointer 
conversion is applicable to rvalue arrays as well, which legalized

     int i = foo().a[0]; /* <- OK in C99 */

but created another issue

     foo().a[0] = 42; /* are we assigning to an rvalue here? */

C99 cops out of this latter problem by stating that the behavior is 
undefined in this case.

-- 
Best regards,
Andrey Tarasevich

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


#161957

FromAndrey Tarasevich <andreytarasevich@hotmail.com>
Date2021-07-17 18:24 -0700
Message-ID<scvvrv$s1r$1@dont-email.me>
In reply to#161939
On 7/16/2021 11:43 AM, Andrey Tarasevich wrote:
> On 7/16/2021 11:22 AM, James Kuyper wrote:
>>
>> I have a vague memory that this wording is connected to a subtle issue
>> with functions that return values of struct type, where the struct
>> contains an array member. But I can't remember what the issue was.
>>
> 
> The issue(s) stem from the combination of the following bits and pieces:
> 
>    1. Function return is always an rvalue
>    2. Member array of an rvalue struct object is also an rvalue
>    3. The result of unary '*' is always an lvalue. And, say, `[]` is 
> defined through unary '*' and '+'.
> 
> 2 and 3 conflict with each other.
> ...

> C99 cops out of this latter problem by stating that the behavior is 
> undefined in this case.

I see that I fell victim to the same confusion I'm carefully trying to 
avoid.

Of course, there's no real conflict between 2 and 3. Value category is a 
property of an expression, not a property of an object. There's nothing 
wrong with having two different expressions that expose the same 
underlying object as an lvalue and as an rvalue at the same time.

C89/90 apparently did not want to introduce the concept of "temporary 
lifetime". That's why it simply prohibited access to arrays inside 
rvalue structs.

C99 decided that this is unnecessarily restrictive, and now we have 
lvalue access to elements of arrays inside rvalue structs. But still C99 
is afraid to allow us to modify these elements. Granted, the use cases 
will always be pronouncedly contrived

   #include <stdio.h>

   struct S { int a[10]; };

   struct S foo()
   {
     return (struct S) { 0 };
   }

   int main()
   {
     int *p;
     p = foo().a, p[5] = 42, printf("%d\n", p[5]); // undefined behavior
   }

but in some corner cases it could have been useful...

-- 
Best regards,
Andrey Tarasevich

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


#161959

FromKeith Thompson <Keith.S.Thompson+u@gmail.com>
Date2021-07-17 20:29 -0700
Message-ID<87wnpo1eq9.fsf@nosuchdomain.example.com>
In reply to#161957
Andrey Tarasevich <andreytarasevich@hotmail.com> writes:
> On 7/16/2021 11:43 AM, Andrey Tarasevich wrote:
>> On 7/16/2021 11:22 AM, James Kuyper wrote:
>>>
>>> I have a vague memory that this wording is connected to a subtle issue
>>> with functions that return values of struct type, where the struct
>>> contains an array member. But I can't remember what the issue was.
>>>
>> The issue(s) stem from the combination of the following bits and
>> pieces:
>>    1. Function return is always an rvalue
>>    2. Member array of an rvalue struct object is also an rvalue
>>    3. The result of unary '*' is always an lvalue. And, say, `[]` is
>> defined through unary '*' and '+'.
>> 2 and 3 conflict with each other.
>> ...
>
>> C99 cops out of this latter problem by stating that the behavior is
>> undefined in this case.
>
> I see that I fell victim to the same confusion I'm carefully trying to
> avoid.
>
> Of course, there's no real conflict between 2 and 3. Value category is
> a property of an expression, not a property of an object. There's
> nothing wrong with having two different expressions that expose the
> same underlying object as an lvalue and as an rvalue at the same time.
>
> C89/90 apparently did not want to introduce the concept of "temporary
> lifetime". That's why it simply prohibited access to arrays inside 
> rvalue structs.

Unless I'm missing something, C89/C90 didn't *prohibit* access to arrays
inside rvalue structs.  The idea was simply overlooked (and it is rather
obscure).  It says that an array expression is converted to a pointer
expression that points to the initial element of "the array object",
overlooking the rare cases when there is no array object to point to.
It was a bug in the standard, fixed in C11.

> C99 decided that this is unnecessarily restrictive, and now we have
> lvalue access to elements of arrays inside rvalue structs. But still
> C99 is afraid to allow us to modify these elements. Granted, the use
> cases will always be pronouncedly contrived
>
>   #include <stdio.h>
>
>   struct S { int a[10]; };
>
>   struct S foo()
>   {
>     return (struct S) { 0 };
>   }
>
>   int main()
>   {
>     int *p;
>     p = foo().a, p[5] = 42, printf("%d\n", p[5]); // undefined behavior
>   }
>
> but in some corner cases it could have been useful...

That was resolved in C11, not C99.  C11 introduced the concept of
"temporary lifetime" for non-lvalue expressions of structure or union
type with an array member.  See N1570 6.2.4p8.

I can't think of any cases where allowing modification of an object with
temporary lifetime would be useful.  In your admittedly contrived
example, if you wanted the struct S object to be persistent, you could
arrange for that easily enough.

(Another approach might have been to add a rule saying that foo().a
yields a pointer of type `const int*`, but that's a bit ugly.)

-- 
Keith Thompson (The_Other_Keith) Keith.S.Thompson+u@gmail.com
Working, but not speaking, for Philips
void Void(void) { Void(); } /* The recursive call of the void */

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


#161960

FromSiri Cruise <chine.bleu@yahoo.com>
Date2021-07-17 21:25 -0700
Message-ID<chine.bleu-2C5905.21251617072021@reader.eternal-september.org>
In reply to#161957
It's easy enough if you extend the type system to include 
lvalueness.

T   Type T.
&T  A T lvalue. & can only appear as the outermost.
*T  A T pointer.

(implied)   &T  -->  T      Load operator.
=           &T=T  -->  T    Assign operator.
&           &T  -->  *T     Address operator.
*           *T  -->  &T     Dereference operator.
(...)       *T(...)  -->  T Derefence and call operator.
[...]       *T[e]  --> &T   Array index.

P u;        Simple declaration of identifier u with type &P.
Q *v;       Declare v with type &*Q.
R w[];      Declare w with type *R.

    (&P)u = (T)e;           Coerce e to (P) and assign.
    (&T)e = (&P)u;          Load u; coerce to T, assign to e.
    (&P)u[...]              [...] not defined for &P or P.
    &(&P)u  -->  (*P)       Address operator.
    *(&P)u                  * not defined for &P or P.

    (&*Q)v = (T)e;          Coerce e to (*Q) and assign.
    (&T)e = (&*Q)v;         Load v; coerce to T, assign to e.
    (&*Q)v[...]  -->  &Q    Load v to (*Q); apply array index.
    &(&*Q)v  -->  (**Q)     Address operator.
    *(&*Q)v  -->  (&Q)      Load v to (*Q) and deref.

    (*R)w = (T)e;           = not defined for *R.
    (&T)e = (*Q)w;          Coerce to T, assign to e.
    (*R)w[...]  -->  &R     Apply array index.
    &(*R)w                  & not defined for *R. By special
                            dispensation the & is ignored and
                            returns (*R)w.
    *(*R)w  -->  (&R)       Apply deref.

-- 
:-<> Siri Seal of Disavowal #000-001. Disavowed. Denied. Deleted.    @
'I desire mercy, not sacrifice.'                                    /|\
Discordia: not just a religion but also a parody. This post         / \
I am an Andrea Doria sockpuppet.                  insults Islam.  Mohammed

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


#161943

FromKeith Thompson <Keith.S.Thompson+u@gmail.com>
Date2021-07-16 15:22 -0700
Message-ID<875yx93nnb.fsf@nosuchdomain.example.com>
In reply to#161938
James Kuyper <jameskuyper@alumni.caltech.edu> writes:
> On 7/15/21 4:21 PM, Andrey Tarasevich wrote:
>> 6.3.2/1 says that
>> 
>>    1 [...] A modifiable lvalue is an lvalue that does not have array 
>> type, [...]
>> 
>> Based on that, arrays are non-modifiable lvalues. We all know what it 
>> actually means. But is there any context in the standard in which this 
>> non-modifiability of array lvalues would actually _matter_, would 
>> actually interact with some other standard requirement?
>> 
>> One thing that comes to mind is a constraint on assignment operators 
>> (6.5.16/2)
>> 
>>    2 An assignment operator shall have a modifiable lvalue as its left 
>> operand.
>> 
>> So, one can combine 6.3.2/1 and 6.5.16/2 and conclude that one can't 
>> assign to arrays. But I believe that constraints are intended/supposed 
>> to be applied after automatic implicit conversions. And since LHS of 
>> assignment is not one of the contexts excluded from array type decay, 
>> said decay is already sufficient to prevent assignment to arrays. 
>
> The Rationale says "the fact that a[i] is a modifiable lvalue while a is
> not has puzzled many students of the language. A more precise
> description was incorporated in C89 in the hope of combatting this
> confusion."
>
> I have a vague memory that this wording is connected to a subtle issue
> with functions that return values of struct type, where the struct
> contains an array member. But I can't remember what the issue was.

I think that case is separate from what we're discussing here, though of
course they're both related to the odd way C treats array expressions.

This thread is about lvalues that are of array type.

The struct return issue is about expressions of array type that are not
lvalues (something that's no longer possible as of C11, I think).

In C90 and C99, if a function returns a struct with a member of array
type and you refer to the name of that member:
    func().array_member
then that's an expression of array type which is converted (in most
contexts) to a pointer to the initial element of "the array object".
The problem: In that specific case there is no array object (a function
call yields a value, not an object).  C11 resolved that by inventing an
object with "temporary lifetime".  There are cases other than function
calls where this shows up; the assignment, comma, and conditional
operators can yield non-lvalues of struct type.

-- 
Keith Thompson (The_Other_Keith) Keith.S.Thompson+u@gmail.com
Working, but not speaking, for Philips
void Void(void) { Void(); } /* The recursive call of the void */

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


#161942

FromKaz Kylheku <563-365-8930@kylheku.com>
Date2021-07-16 22:21 +0000
Message-ID<20210716145835.570@kylheku.com>
In reply to#161918
On 2021-07-15, Andrey Tarasevich <andreytarasevich@hotmail.com> wrote:
> 6.3.2/1 says that
>
>    1 [...] A modifiable lvalue is an lvalue that does not have array 
> type, [...]
>
> Based on that, arrays are non-modifiable lvalues. We all know what it 
> actually means. But is there any context in the standard in which this 
> non-modifiability of array lvalues would actually _matter_, would 
> actually interact with some other standard requirement?

If what you are getting at is this: could a C dialect provide complete
support for array passing, returning and assignment, while conforming
to the current standard?

The answer is no.

A conforming extension of behavior could be to allow arrays to be
modifiable lvalues: emit the required diagnostic, and then allow
assignment or initialization; e.g.

  int a[10] = { 0 };
  int b[10] = a;
  int c[10];
  c = b;

FUrthermore, function declaration syntax for returning arrays could
be added without conflict:

  int foo(void)[10];
  c = foo();

Where we run aground is the fact that parameter declarations of
array type actually declare a pointer. This is the case even
if they specify a dimension:

  void foo(int a[42]); // actually (int *a)

that kind of puts a monkey wrench into an otherwise reasonably
tidy plan to extend the language.

Passing arguments to parameters is very similar to assignment;
An assignable array proposal which doesn't permit passing would
introduce an ugly inconsistency.

> So, one can combine 6.3.2/1 and 6.5.16/2 and conclude that one can't 
> assign to arrays. But I believe that constraints are intended/supposed 
> to be applied after automatic implicit conversions. And since LHS of 
> assignment is not one of the contexts excluded from array type decay, 
> said decay is already sufficient to prevent assignment to arrays.

Indeed, an implementation can implement the constraint that arrays are not
modifiable lvalues simply by imposing the "decay rule" in all contexts
other than when the array is the operand of & (address-of) or sizeof.

The array is then not assignable by virtue of having been converted
to a pointer which is not an lvalue. If it's not an lvalue, it's not
a modifiable lvalue: requirement satisfied.

> Am I right here? Is the constraint of 6.5.16/2 supposed to be applied 
> before automatic implicit conversions or after them?

It looks moot. Before conversion to pointer, you have an array lvalue,
and the requirement says that it' not modifiable. Thus, cannot assign to
it. After conversion to pointer, you don't have an lvalue. Not
assignable, either.

Which case it is basically is only germane to the wording of the
constraint violation diagnostic, and that is not specified.

A compiler which diagnoses the assignment as "cannot assign to a
calculated pointer" is conforming; it has produced the required
diagnostic.

-- 
TXR Programming Language: http://nongnu.org/txr
Cygnal: Cygwin Native Application Library: http://kylheku.com/cygnal

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


#161944

FromAndrey Tarasevich <andreytarasevich@hotmail.com>
Date2021-07-16 23:27 -0700
Message-ID<sctt7r$88g$1@dont-email.me>
In reply to#161942
On 7/16/2021 3:21 PM, Kaz Kylheku wrote:
> If what you are getting at is this: could a C dialect provide complete
> support for array passing, returning and assignment, while conforming
> to the current standard?
> 
> The answer is no.

No, no, no, I'm not interested in that at all.

>> Am I right here? Is the constraint of 6.5.16/2 supposed to be applied
>> before automatic implicit conversions or after them?
> 
> It looks moot. Before conversion to pointer, you have an array lvalue,
> and the requirement says that it' not modifiable. Thus, cannot assign to
> it. After conversion to pointer, you don't have an lvalue. Not
> assignable, either.
> 

Yes, it is moot for the specific case of arrays.

But at the same time it intuitively looks and feels like a more general 
issue. Again, what comes first: automatic implicit conversions or 
constraint checks?

And even if this currently proves to be moot in all other contexts as 
well, it still appears to be something kinda... too important to be left 
unspecified.

-- 
Best regards,
Andrey Tarasevich

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


Page 1 of 2  [1] 2  Next page →

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


csiph-web