Keith said:
Skarmander said:
Keith said:
Keith Thompson wrote:
[...]
6.5.4.2 says you can't apply unary "&" to a register-qualified
object.
6.3.2.1 says that the implicit conversion of an array expression to a
pointer to its first element invokes undefined behavior if the
designated array object has register storage class. (I'm not sure why
it's undefined behavior rather than a constraint violation.)n
So is this code acceptable in C99?
#include <stdio.h>
int main(void)
{
register int a[2] = {
printf("%zu\n", sizeof *a),
printf("%zu\n", sizeof a)
};
return 0;
}
Since it's a normal array, and not a variable-length array, the
expression *a should never be evaluated, but just the type examined to
determine its size.
Well, *I* certainly wouldn't accept it.
}
But yes, I believe it's legal (no constraint violations, no undefined
behavior, but implementation-defined behavior because the output
depends on sizeof(int)).
<OT>
gcc complains "error: address of register variable 'a' requested" on
"sizeof *a". I believe gcc is wrong, but of course spurious
diagnostics don't make an implementation non-conforming.
</OT>
I believe gcc is not wrong and that there *is* undefined behavior. I'm
not a language lawyer, so see if you can poke holes in this.
"Except when it is the operand of the sizeof operator or the unary &
operator, or is a string literal used to initialize 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. If the array object has register
storage class, the behavior is undefined."
Now *do not* tell me about the "except when it is the operand of the
sizeof operator" part. I *read it*. In the expression `sizeof *a', `a'
*is not* the operand of the sizeof operator -- `*a' is. Although `*a'
is not evaluated, its type must be determined. In order to do that,
`a' must be converted to a pointer (otherwise `*a' is a constraint
violation) and this conversion invokes undefined behavior.
I don't think so. Any conversion would be part of the evaluation of
the expression.
This I dispute. The standard does not mark conversion as belonging
exclusively to the evaluation process.
Because the expression "*a" as a whole is not evaluated, the conversion doesn't take place.
I agree that neither `a' nor `*a' are evaluated.
The compiler is (and must be) perfectly capable of determining the
type, and therefore the size, of the expression without actually
evaluating it.
I would be inclined to agree with you if you pointed out the rules in
the standard that specify what type `*a' has in this case, without
requiring any conversion.
The compiler can only determine the type according to the rules laid
down for this in the standard. The only rule I can find that specifies
what the type of `*a' is is given in 6.5.3.2.4: "[..] If the operand has
type 'pointer to type', the result has type 'type'." The constraints
specify that "the operand of the unary * operator shall have pointer
type", so that this type determination always applies.
But `a' is not of pointer type -- without conversion, `*a' is a
constraint violation. `a' is *not* the operand of a sizeof operator but
of an `*' operator, therefore it is converted to an `int*' per
6.3.2.1.3, and invokes undefined behavior per the same.
If you believe an alternate mechanism is required or supplied by the
standard that the compiler can apply to determine the type without going
through conversion, I'd like to know. I don't see what magically tells
the compiler what the type of `*a' is without tripping over the
conversion rules.
You can try and argue that the conversion is (part of) evaluation and
the compiler has only to *act* as if it converted for the sake of type
calculation, but must not actually do so. This is an eminently
reasonable approach, but it's made up out of whole cloth; the standard
doesn't say this is how determining types can be done. We are then
claiming the part about undefined behavior should be ignored without
having anything in the standard to back us up on this.
I repeat: I agree that neither `a' nor `*a' is actually evaluated, but I
do not agree that conversion could or should only happen on evaluation,
and I also argue that the conversion is necessary in this case. If this
is not the intent of the standard, I think it does not clearly specify
how the types of expressions are to be determined.
For contrast, consider `sizeof (0 / 0)'. The type of `0 / 0' can be
deduced by sections in the standard (namely 6.4.4.1, 6.3.1.8 and the
lack of any special provisions on the result type in 6.5.5) without
needing 6.5.5.5, which specifies UB for determining the result of a
division by zero. This is irrelevant because we do not evaluate the
expression and do not determine a result. Therefore `sizeof (0 / 0)' is
a well-defined expression equivalent to `sizeof int'. A similarly
careful analysis does not seem to give us any typing information for
`*a' that doesn't involve a clause with undefined behavior.
(We could take this to comp.std.c., it's getting rather technical.)
S.