Post by Woong JunPost by Wojtek LerchPost by Woong JunPost by Wojtek Lerch...
Post by Woong JunI believe this is what the standard intends to specify for static
1. For static initializers of arithmetic types,
- only constant operands of arithmetic types are allowed; and
- only casts between arithmetic types are allowed.
Where does the standard forbid the initializer for a _Bool to be an
address constant?
It does not forbid. The same effect can be achieved by removing from
my description the type restrictions for initializers. I dropped the
pointer-to-_Bool conversion because it looks inconsistent to me to
allow an address constant for a _Bool initializer disallowing
pointer comparisons.
Are you saying that the standard allows them unintentionally?
No. I'm saying I dropped them because I just thought them
inconsistent with the policy that I believed to exist behind the spec
for static initializers, that is, compilers need not know about
addresses. This never means that the committee mistakenly allowed an
address constant for _Bool initializers.
My understanding is that the policy behind address constants was to
match the lowest common denominator of what linkers were capable of
doing -- which was compute the address of a symbol plus a constant. But
in an initializer for _Bool, the compiler doesn't need the linker's
help, because all it needs to know is whether the value is a null
pointer or not.
Post by Woong JunPost by Wojtek LerchI guess it's not impossible that the Committee simply forgot to add
words to specifically forbid using an address constant to initialize a
_Bool.
Agreed.
... but if it did occur to them, I can't think of a good reason to
consider it important enough to add more words to the text.
[...]
Post by Woong JunPost by Wojtek LerchPost by Woong JunPost by Wojtek LerchThere should be a restriction on the arithmetic operand to [], but I
int arr[2], *ptr = &arr[ sin(0)==0 ];
The pointer is created explicitly using the unary & operator, points to
an object of static storage duration, and the value of an object is not
accessed by use of the [] operator. I doubt this was meant to be
allowed, but what restriction does it violate?
This is not clear from the text of the standard, which is one of the
reasons I started this thread. I think, however, it is convincible
that [] is a mere syntactic sugar for pointer addition and
indirection so the restriction for pointer addition is still imposed.
But my concern was not specifically about the [] operator but generally
about integer subexpressions in address constants. The expression
"arr+(sin(0)==0)", just like the expression "&arr[sin(0)==0]", is a
pointer to an object of static storage duration; but it is not an
address constant, is it? But why not?
I don't think you are asking a practical reason why only ICEs are
permitted as the integer part for pointer addition on most compilers.
Correct: I think I know what the practical reason is. My concern is
that I don't see where that restriction is stated in the standard.
Post by Woong JunAre you saying that, with the current wording of the standard,
(arr+(sin(0)==0)) is a valid address constant because it is evaluated
to a pointer to a static object? Or that the wording in problem
should change to endorse that expression in the next revision?
No, I was concerned that (arr+(sin(0)==0)) was a valid address constant
according to the text, even though I don't think it should be; but I
think I was mistaken, because it violates 6.6#3.
But I can think of other examples that don't violate 6.6#3 or any other
words of the standard (as far as I can tell) but I strongly suspect that
they were not meant to be considered valid address constants. Here's an
one that GCC rejects:
extern int arr1[5], arr2[5];
static int *ptr = &arr1[ arr1+5==arr2 ];
If there some requirement that I haven't noticed this violates?
Post by Woong JunIf the former is the case, in order to preclude such an expression,
the wording should be revised to separately specify how addresses
(pointers) can be generated and which operations are allowed to
apply to them.
Yes, I think that would be nice. Personally I don't see a good reason
to allow anything other than an ICE in the integer part of an address
constant. That would be consistent with the fact that an initializer
can be an adress constant plus minus an ICE -- allowing more freedom to
the integer part of the address constant than to the integer added to it
doesn't make sense to me.
Post by Woong JunIf the latter, the current restriction on ICE looks reasonable
considering practical implementations for static initializers.
It looks invisible to me... Can you help me find it?
Or is your interpretation that "&arr[exp]" used as an initializer must
be interpreted as address constant "arr" plus ICE "exp", as opposed to
the whole "&arr[exp]" being an address constant with no separate ICE
added to it? I have to say that I see no support in the standard for
such an interpretation (even though I think it would be a very
reasonable requirement).
Post by Woong Jun[...]
Post by Wojtek LerchPost by Woong JunPost by Wojtek LerchAny unevaluated part, or just any operand to sizeof?
static int i = 0 && printf("Hello") ? printf("world!\n") : 0;
Any unevaluated part including an operand of sizeof for consistency.
But the standard does not specify an exemption for any unevaluated parts
other than operands of sizeof; are you saying that's unintentional?
Yes, I think it is because allowing unevaluated parts to be
ignored eases implementations; and I believe this is why we got
Constant expressions shall not contain assignment, increment,
decrement, function-call, or comma operators, except when they
are contained within a subexpression that is not evaluated.
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
I don't know; the compiler has to completely parse the syntax anyway.
Having to know that the constraint only applies to certain parts of the
expression sounds like a complication to me, not a simplification. But
I guess that may depend on how you write your compiler.
Post by Woong Juninstead of similar one to C90's. I know that the wording change from
"an operand of sizeof" to "an unevaluated subexpression" originally
came from covering VLAs, but IIRC the committee intentionally left
the wording untouched even if it was indicated that the wording
should be revised to "within an operand of sizeof that is not
evaluated" or something like that.
"A sizeof operator whose result is an integer constant" is the wording
used in 6.6#8; I find it messy because it's a reference to a distant and
non-trivial part of the spec, but it does the job.
Post by Woong JunPost by Wojtek LerchPost by Woong JunDifferently from C90, C99 even allows assignments or function calls
static int *p = 0 && ((void (*)())0)(); // valid in C99
Does it? As far as I can tell, the above is not a null pointer, a
pointer to an lvalue designating an object of static storage duration,
or a pointer to a function designator. What makes it an address constant?
static int i, *p = (1)? &i: ((int *(*)())0)(); // valid in C99
Yes, since the function call is not evaluated, the constraint of 6.6#3
does not apply here, and therefore I have to admit, reluctantly, that
this example is valid. Personally I would prefer sizeof to be the only
exception allowing function calls.
Post by Woong JunAn address constant is a semantic entity (as opposed to ICE or ACE)
and thus "(shall) evaluate to" applies.
I'm not sure if I understand what a "semantic entity" is. Is an address
constant not an expression in the source code?
My impression has been that the standard is generally not very pedantic
about the distinction between expressions and their values, and I have
always assumed that the definition of "address constant" just talks
about expressions in a somewhat sloppy way. Obviously, there can't be
such a thing as "a pointer to an lvalue" or "a pointer to a function
designator" -- lvalues and function designators are expressions, and a
pointer can't point to a sequence of tokens in the source code. I have
always assumed that "a pointer to X" in this definition really means the
expression &X -- is that an oversimplification?
(I have a similar issue with the descriptions of the various operators
saying that the *result* of the operator, as opposed to the expression
containing it, is an lvalue. I have always assumed that that was
because the text wasn't completely translated from C90, where "lvalue"
was in fact defined as the result of an expression (the identity of the
object that the expression designates) rather than the expression
itself. The same excuse would apply to what I see as a slopiness in the
wording here as well. Am I completely misinterpreting this?)
[...]
Post by Woong JunMy literal reading of the standard is implemented in my
compiler and it gives this result in regard to unevaluated parts of
static int *p = 0 && (3.14+0); /* invalid */
static int i, *q = (1)? &i: ((int *(*)())0)(); /* valid */
static int j = 1 || (&i == 0); /* invalid */
Other major compilers silently accept the last one; I don't know if
it is intentional.
Intentional or not, the compiler has an excuse: 6.6#10 "An
implementation may accept other forms of constant expressions." Also,
because the requirement that an initializer shall be an ACE is not a
constraint, violating it triggers undefined behaviour without a
mandatory diagnostic, doesn't it?
Incidentally, I just recently ran into a case where GCC surprised me by
happily compiling code similar to this:
static const int a = offsetof(x,y);
static const int b = a + offsetof(p,q);
except when I turned off optimization. I was thinking about it as a
compiler bug until I realized that 6.6#10 makes it a feature...
Post by Woong Jun[...]
Post by Wojtek LerchPost by Woong JunPost by Wojtek LerchPost by Woong JunNote that
static _Bool b = &b;
is precluded by item 1, and all pointer comparisons are not allowed.
But this is not a comparison, it's a conversion.
Yes, it's a conversion but nominally. The standard specifies
comparsion to 0 is performed for the conversion.
"all pointer comparisons are not allowed", did you mean comparison
operators, or did you mean all operations whose descriptions use the
phrase "compares equal"?
The latter based on the policy I said above.
I'm sorry but I'm not sure which policy you're referring to... I
understand that comparison operators are not on your list of allowed
operators (even though they're not on C99's list of forbidden
operators), and I have to admit that I'm too lazy to actually search the
standard for all occurrences of "compare equal", but here we are talking
about a conversion that is applied to the value of the address constant,
and its validity is independent of the operations that are allowed in an
address constant.