int i;
n = is_moon_waxing ? NULL : &i;
Perhaps if you read the defect reports that I referenced you would. Those
reports are #012, #076 and #106, the one dealing specifically with this
case being #076.
[snip]
It just means that the Standard had its problems, that's why they
keep correcting it. It still has...
I only have access to n869 and the C89 draft. n869 has no 6.2.2.1 and
the C89 draft has different numbering, so I don't know where to find that
paragraph. Quote it if you can.
In the C89 draft that would be 3.2.2.1 par 2. It's basically
the same as C99 6.3.2.1#2.
Given the defect reports though, the behaviour required under C90 is clear.
I don't see any cv in C90 except that `*n' is
not strictly an lvalue, which cannot (in general) be established at
compile time (due to poor definition of an lvalue).
That's significant enough to prevent the program from being conforming, so
why downplay it?
Defect report #076:
"Subclause 6.3.3.2 requires the operand of &to be an lvalue; NULL is
not an lvalue. [...] [Therefore t]he use of [the construct *n where n ==
NULL] prevents a program from being strictly conforming..."
Yes, I can only agree with it. And all compilers should issue
whatever diagnostic each time, just in case, or else they'll risk
violating the Standard.
How could evaluating "*" - in the case where "&*" is not a no-op -
not result in taking a value?
Evaluating "*" and taking a value are two different processes.
1. The result of "*" is an lvalue (or function designator) (6.5.3.2#4).
2. If a (non-array) lvalue is not an operand to "&", "++", "--", "." or
"=", it is "converted to the value stored in the designated object
(and is no longer an lvalue)" (6.3.2.1#2) (that's when the value
is read).
Perhaps you would accept this as a clarification/expansion: at compile
time it is established whether the "*" operator results in an lvalue, but
it cannot always be established that it is legal to evaluate that lvalue.
At runtime evaluating that lvalue may in some cases be illegal.
Also the definition of the indirection operator is lacking in the case of
pointer to incomplete struct.
N869, 6.5.3.2#4:
The unary * operator denotes indirection. If the
operand points to a function, the result is a function
designator; if it points to an object, the result is an
lvalue designating the object. If the operand has type
``pointer to type'', the result has type ``type''. If an
invalid value has been assigned to the pointer, the behavior
of the unary * operator is undefined.74)
In this case, the operand points to neither a function nor an object,
since an incomplete type cannot be an object (as implied by the definition
of lvalue).
Pointers to incomplete types may point to objects. An object is
simply a range of storage (see the definition somewhere in clause 3.).
So all that is specified in this case is the type. This is
where I would have expected to find wording to the effect of "if it points
to an incomplete type, the result is that a syntax error occurs except in
cases where the & operator is immediately applied".
No, the result is just an lvalue of incomplete struct type.
The value is not accessed yet. You have a bad idea of what lvalues
are. They can be incomplete type - see again the definition at the
top of this article.
It's not quite true perhaps; UB is invoked when an lvalue that doesn't
designate an object is evaluated. It seems that by not evaluating "*"
the Standard wants to accomodate invalid pointers (cf. result of "*").
Only in C99 - this is not true in C90 as the defect reports clarify.
Yes, I was writing this only in context of C99.
It's not strange, but without the &* no-op, it's invalid. In 6.3.2.1 as
quoted top of post: "if an lvalue does not designate an object when it is
evaluated, the behavior is undefined." Since *ps represents an incomplete
type, it cannot be an object. Therefore the behaviour is undefined.
Not automatically, only when the lvalue is evaluated.
`*ps' is not an object; `ps' may point to an object, `*ps' is
an lvalue designating that object ("lvalue" == think "pointer").
When operands to "&", lvalues are not evaluated.
So 6.3.2.1 is effectively saying, "an expression with incomplete type is
an lvalue, but cannot be evaluated as one". Which is pretty meaningless
except for the &* case.
(and except when the incomplete lvalue is an array type)
Generally, yes, I think. There doesn't seem much you can do
with incomplete lvalues.
Sorry, I was wrong for C99 here, but it holds for C90, and for other
operators where lvalue is required ("++", "--", "="). See below.
So we could say that *ps is known in advance to be an lvalue but its
evaluation as such is prohibited.
Precisely, that's how I would like to see it.
But note that the C99 Standard handles this in a different manner for
"&" operator (and is slightly inconsistent in words). It says its
operand must be (among others) the result of "*" operator, and "*"
(in "&*") is not evaluated. This way it tries to weasel out of trouble
of special cases (such as in the above DRs). I don't see anything
that is technically wrong with this.
Maybe you have a point above: since "*" is not evaluated, we don't
really know if `*ps' is an lvalue. But OTOH the subexpression `*ps'
is an expression and the question whether it is an lvalue is valid.
Everything indicates that it is.
One more example:
extern struct s s;
struct s *ps = &s;
*ps; //UB
The last line raises UB because lvalue `*ps' is incomplete type
(and cannot be converted to a value; the last sentence of 6.3.2.1).
What I mean to show is that in order to explain why UB arises, first
you have to assert that `*ps' is lvalue (which is actually trivial,
for the result of "*" is always an lvalue, so there's no question
about it here).
All this is very confusing, especially that there's no good
definition of lvalue in the Standard. I get confused too.
You have to have a brain size of a planet to understand C lvalues
- undoubtedly I don't.