jimbo@tandem.com (Jim Lyon) (03/13/91)
In article <31306@shamash.cdc.com> bls@u02.svl.cdc.com (Brian Scearce) writes: >The rules are pretty easy (especially if you have your copy of >Harbison and Steele on your desk :-) > >0. variable names (excepting function, array and enum constant > names) are lvalues. >1. e[k] is an lvalue, regardless of whether e and k are lvalues. >2. (e) is an lvalue iff e is. >3. e.name is an lvalue iff e is. >4. e->name is an lvalue regardless of whether e is an lvalue. >5. *e is an lvalue regardless of whether e is an lvalue. Rules (1) and (5) need to be further qualified. e[k] and *e are lvalues regardless of whether e and k are lvalues, UNLESS the type of e[k] or *e is either Array... or Function... For example, if A is declared as "int A[10][10]", then "A[5]" is not an lvalue, because the type of "A[5]" is "Array of int". -- Jim Lyon jimbo@Tandem.Com
torek@elf.ee.lbl.gov (Chris Torek) (03/14/91)
>In article <31306@shamash.cdc.com> bls@u02.svl.cdc.com (Brian Scearce) writes: >>The rules are pretty easy (especially if you have your copy of >>Harbison and Steele on your desk :-) [and then notes that this needs changes for ANSI C] >>0. variable names (excepting function, array and enum constant >> names) are lvalues. In ANSI C, arrays are also lvalues (but not modifiable lvalues). This is conceptually required to make sizeof() work without throwing in weird rules. (One can always argue that `non-modifiable lvalues' is a weird rule :-) ) >>1. e[k] is an lvalue, regardless of whether e and k are lvalues. >>2. (e) is an lvalue iff e is. >>3. e.name is an lvalue iff e is. >>4. e->name is an lvalue regardless of whether e is an lvalue. >>5. *e is an lvalue regardless of whether e is an lvalue. In article <1991Mar13.050555.26149@tandem.com> jimbo@tandem.com (Jim Lyon) writes: >Rules (1) and (5) need to be further qualified. e[k] and *e are >lvalues regardless of whether e and k are lvalues, UNLESS the type >of e[k] or *e is either Array... or Function... Half of the qualifier is correct for ANSI C (*e is not an lvalue if e has type `pointer to function (args) returning T'). In addition, the type of e[k] may never% be `function ...' because for this to be true, either: e has type `pointer to function ...' and k has an integral type or: e has an integral type and k has type `pointer to function ...' and you cannot add an integer value to a pointer-to-function-... since the size of a `function-...' is unknown.& ----- % Well, maybe never. Since *p \equiv *(p + 0) \equiv p[0], one could claim that int (*fp)(void); ... (fp[0])(); should have the same effect as `(*fp)();'. I do not know what rules X3.159-1989 gives here (my copy is in my office; I am not). Thus, if either e or k is the integral constant 0, perhaps e[k] may have type `function (args) returning T'. & GCC permits adding integers to function-pointer values, by pretending the pointers are byte pointers. This feature is of dubious utility (if you wanted to do that you could just cast to `char *' and back). -- In-Real-Life: Chris Torek, Lawrence Berkeley Lab EE div (+1 415 486 5427) Berkeley, CA Domain: torek@ee.lbl.gov
sarima@tdatirv.UUCP (Stanley Friesen) (03/15/91)
In article <1991Mar13.050555.26149@tandem.com> jimbo@tandem.com (Jim Lyon) writes: <In article <31306@shamash.cdc.com> bls@u02.svl.cdc.com (Brian Scearce) writes: <>0. variable names (excepting function, array and enum constant <> names) are lvalues. <>1. e[k] is an lvalue, regardless of whether e and k are lvalues. <>2. (e) is an lvalue iff e is. <>3. e.name is an lvalue iff e is. <>4. e->name is an lvalue regardless of whether e is an lvalue. <>5. *e is an lvalue regardless of whether e is an lvalue. < <Rules (1) and (5) need to be further qualified. e[k] and *e are <lvalues regardless of whether e and k are lvalues, UNLESS the type <of e[k] or *e is either Array... or Function... Well, as I understand the ANSI definition of lvalue (different than the K&R1 definition), the original rules are correct as stated. It is just that in that case the result is not a *modifiable* lvalue, and is converted in all value contexts into a pointer to the object. <For example, if A is declared as "int A[10][10]", then "A[5]" <is not an lvalue, because the type of "A[5]" is "Array of int". Or rather, by ANSI definitions, it *is* an lvalue that is immediately converted into a non-lvalue pointer of type "Pointer to int". -- --------------- uunet!tdatirv!sarima (Stanley Friesen)
scc@rlgvax.Reston.ICL.COM (Stephen Carlson) (03/15/91)
In article <1991Mar13.050555.26149@tandem.com> jimbo@tandem.com (Jim Lyon) writes: >In article <31306@shamash.cdc.com> bls@u02.svl.cdc.com (Brian Scearce) writes: >>The rules are pretty easy (especially if you have your copy of >>Harbison and Steele on your desk :-) >> >>0. variable names (excepting function, array and enum constant >> names) are lvalues. >>1. e[k] is an lvalue, regardless of whether e and k are lvalues. >>2. (e) is an lvalue iff e is. >>3. e.name is an lvalue iff e is. >>4. e->name is an lvalue regardless of whether e is an lvalue. >>5. *e is an lvalue regardless of whether e is an lvalue. > >Rules (1) and (5) need to be further qualified. [ Points well taken deleted, please refer to original article. ] Rules (1) and (4) are technically redundant. Since e[k] <=> *((e)+(k)), rule (1) is a special case of Rule (5). Since e->name <=> (*e).name, rule (4) is a special case of Rules (3), (2), and (5): *e must be an lvalue By rule 5 => (*e) must be an lvalue By rule 2 => (*e).name must be an lvalue By rule 3 => e->name must be an lvalue By definition of -> Hence, rule (4). However, it is better to present a practical set of rules than a logically minimal set of rules. -- Stephen Carlson | ICL OFFICEPOWER Center | In theory, theory and scc@rlgvax.reston.icl.com | 11490 Commerce Park Drive | practice are the same. ..!uunet!rlgvax!scc | Reston, VA 22091 |
sean@hcx2.ssd.csd.harris.com (Sean Burke) (03/16/91)
In article <10898@dog.ee.lbl.gov>, torek@elf.ee.lbl.gov (Chris Torek) writes: |> >In article <31306@shamash.cdc.com> bls@u02.svl.cdc.com (Brian Scearce) writes: |> >>The rules are pretty easy (especially if you have your copy of |> >>Harbison and Steele on your desk :-) |> |> [and then notes that this needs changes for ANSI C] |> |> >>0. variable names (excepting function, array and enum constant |> >> names) are lvalues. |> >>1. e[k] is an lvalue, regardless of whether e and k are lvalues. |> >>2. (e) is an lvalue iff e is. |> >>3. e.name is an lvalue iff e is. |> >>4. e->name is an lvalue regardless of whether e is an lvalue. |> >>5. *e is an lvalue regardless of whether e is an lvalue. |> |> In article <1991Mar13.050555.26149@tandem.com> jimbo@tandem.com |> (Jim Lyon) writes: |> >Rules (1) and (5) need to be further qualified. e[k] and *e are |> >lvalues regardless of whether e and k are lvalues, UNLESS the type |> >of e[k] or *e is either Array... or Function... |> |> Half of the qualifier is correct for ANSI C (*e is not an lvalue if e |> has type `pointer to function (args) returning T'). In addition, the |> type of e[k] may never% be `function ...' because for this to be true, |> either: |> |> e has type `pointer to function ...' and k has an integral type |> |> or: |> |> e has an integral type and k has type `pointer to function ...' |> |> and you cannot add an integer value to a pointer-to-function-... since |> the size of a `function-...' is unknown.& |> So where would: struct { int array[10] ; } func() ; func().array[k] fit into these rules? I guess you could argue that its covered becuase func().array is implicitly taking the address of something that is not an lvalue, and thats an error in itself.
torek@elf.ee.lbl.gov (Chris Torek) (03/16/91)
In article <2647@travis.csd.harris.com> sean@hcx2.ssd.csd.harris.com (Sean Burke) writes: >So where would: > > struct { int array[10] ; } func() ; > > func().array[k] > >fit into these rules? > >I guess you could argue that its covered becuase > > func().array > >is implicitly taking the address of something that is not an lvalue, >and thats an error in itself. This is correct. X3.159-1989%, p. 40: A postfix expression followed by a dot . and an identifier designates a member of a structure or union object. ... is an lvalue if the first expression is an lvalue. Thus, `func().array' denotes something that is not an lvalue but would (if it existed) be a value of type `array N of ...'. Since no such type exists, it is clear that no expression of the form func().array exists. :-) Seriously: the value from func() is an `rvalue' structure and an attempt to name its `array' member is illegal. GCC permits it as an extension. ----- % Actually, I am still using a 1988 draft. -- In-Real-Life: Chris Torek, Lawrence Berkeley Lab CSE/EE (+1 415 486 5427) Berkeley, CA Domain: torek@ee.lbl.gov