JTC1/SC22/WG14
N676
Document Number: WG14 N676/X3J11 97-039
General wording issues (clauses 1 to 6)
Abstract
========
This document is an attempt to identify all the minor issues I can find
in clauses 1 to 6 of the Standard. I am using draft 9 pre 3 as my
starting point.
It omits those items which I have previously proposed, or have been
addressed in a DR. It also omits a couple of matters which I am handling
separately.
There will be one or more companion papers for subclause 7 and the
annexes.
I hope it is unnecessary to produce formal proposals for all of these,
but I will attempt to identify the issue and have usually generated new
wording (I hope that, in at least some cases, the new wording will make
the problem obvious).
=======================================================================
Item 1:
The term "access" is not well defined. From context, it sometimes
appears to mean "read the value", and sometimes "read or write the
value". This ambiguity sometimes makes it hard to understand what is
actually meant.
There needs to be a definition in clause 3, and all uses of the term
need to be checked for the read-only / read-write problem. Probably the
best approach is to define it as "read or write", and to find and fix
the places where "read" is meant.
====
Item 2:
Change the first part of paragraph 1 of subclause 5.1.2.2.1 to:
The function called at program startup is named /main/. The
implementation declares no prototype for this function. It shall be
defined either with no parameters:
...
int main (int argc, char *argv[]) { /* ... */ }
or equivalent [*], or in some other implementation-defined manner.
[*] Thus /int/ can be replaced by a typedef-name defined as /int/,
or the type of argv can be written as /char **argv/, and so on.
This will make it clear that, while these are the only permitted
strictly conforming alternatives, extensions are allowed but must be
documented.
====
Item 3:
Examples 2 and 6 in subclause 5.1.2.3 need rewording. At present they
use the term "exception" to mean something like an overflow trap,
whereas 6.3 makes it clear that an "exception" occurs on overflow even
when the result is silently wrapped.
====
Item 4:
In 5.2.1 paragraph 2, delete the final "literal". The zero character
terminates strings, but does not occur in a string literal (which is a
syntactic construct).
====
Item 5:
Subclause 6.1.2 treats the term "identifier" as representing the
sequence of characters. On the other hand, subclause 6.1.2.1 treats the
term as representing that sequence within a given scope. Thus in:
{
int fred; /* fred-1 */
{
int fred; /* fred-2 */
}
}
6.1.2 paragraph 8 treats fred-1 and fred-2 as being the same identifier,
while 6.1.2.1 treats them as different.
The term "lexically identical identifiers" appears in 6.1.2.1 paragraph
3. This should be used whenever the meaning of 6.1.2 is intended (this
applies in several places throughout the Standard, not just in 6.1.2).
====
Item 6:
In 6.1.2.5, delete the last sentence of paragraph 2 and append to
paragraph 11:
The implementation shall define /char/ to have the same range,
representation, and behaviour as one of /signed char/ and /unsigned
char/. [*]
[*] CHAR_MIN, defined in <limits.h>, will have one of the values 0
or SCHAR_MIN, and this can be used to distinguish the two options.
Irrespective of the choice made, /char/ is a separate type from the
other two, and is not compatible with either.
This clarifies that there are only two differently-behaving types, not
three.
====
Item 7:
The rules for composite type handle an incomplete array meeting a
complete one, but not the equivalent situation with an incomplete
structure or union.
Replace subclause 6.1.2.6 paragraph 3, first bullet point, with:
- If one type is complete and the other type is incomplete, the
composite type is a complete type.
====
Item 8:
Add the following to the end of subclause 6.2.2.3:
An integer may be converted to any pointer type. The result is
implementation-defined, and might not be a pointer to an object
of that type. [59]
Any pointer type may be converted to an integral type; the result is
implementation-defined, and need not be in the range of values of
any integral type. If the resulting value cannot be represented in
the destination type, the behaviour is undefined. [*]
[*] Thus if the conversion is to /unsigned int/ but yields a
negative value, the behaviour is undefined.
A pointer to a complete or incomplete object type may be converted
to a pointer to a different complete or incomplete object type. If
the resulting pointer is not correctly aligned for the pointed to
type, the behaviour is undefined. Otherwise, when converted back
again, the result shall compare equal to the original pointer. [*]
[*] All pointers to character types are correctly aligned. In
general, the concept "correctly aligned" is transitive: if a pointer
to type A is correctly aligned for a pointer to type B, which in
turn is correctly aligned for a pointer to type C, then a pointer to
type A is correctly aligned for a pointer to type C.
A pointer to a function ... [this paragraph, taken from 6.3.4,
remains unchanged].
Note: the idea that implementation-defined behaviour can be required to
be undefined is a rather unsettling one. Given the existence of the
types intptr_t and uintptr_t in subclause 7.4.4, it may be worth
replacing the second of these new paragraphs by:
Any pointer type may be converted to an integral type; the result is
implementation-defined, but will be in the range of the signed
integral type /intptr_t/. If the destination type is any other
integral type, the value is converted to /intptr_t/ and then to the
destination type.
and omitting the relevant footnote.
Delete 6.3.4 paragraph 4, and add the following paragraph to the
constraints (after paragraph 2):
Conversions that involve pointers, other than where permitted by the
constraints of 6.3.16.1, shall be specified by means of an explicit
cast.
====
Item 9:
In 6.3.2.3 paragraph 5, replace:
With one exception, if a member of a union object is accessed after
a value has been stored in a different member of the object, the
behaviour is implementation-defined. [54] One special guarantee is
made ...
with:
With one exception, if the value of a member of a union object is
used when the most recent store to the object was to a different
member, the behaviour is implementation-defined. [54] One special
guarantee is made ...
Alternatively, since some implementations apparently have problems with
this clause, replace it with:
With two exceptions, if the value of a member of a union object is
used when the most recent store to the object was to a member whose
type does not have the same alignment and representation, the
behaviour is undefined. If either member has character type or is
an array of character type, the behaviour is implementation-defined.
[54]. Furthermore, one special guarantee is made ...
====
Item 10:
Replace subclause 6.5.2 paragraph 4 by:
Each of the comma-separated sets designate the same type, except
that for bit-fields, it is implementation-defined whether the
specifier /int/ (or no specifier) is the same type as /signed int/
or is the same type as /unsigned int/.
Replace subclause 6.5.2.1 paragraph 8 by:
A bit-field shall have a type that is a qualified or unqualified
version of /signed int/ or /unsigned int/. A bit field is
interpreted as a signed or unsigned integral type consisting of the
specified number of bits. [*]
[*] As specified in 6.5.2 above, if the actual type specifier used
is /int/ or there is no type specifier, or is a typedef-name defined
using either of these, then it is implementation-defined whether the
bit-field is signed or unsigned.
This eliminates the duplicate wording in these two places, and also
makes it clear that there is not a potential third signedness of
bitfield.
If my proposals for representation of types are accepted, there may need
to be further wording adjustments in the second alteration.
====
Item 11:
In subclause 6.5.2.1, change paragraph 3 to read:
... shall not exceed the number of bits in an object of the type
that would be specified if the colon and expression had been
omitted. If the value is zero ...
The current wording doesn't say *what* the type is compatible with.
====
Item 12:
Subclause 6.5.2.2 allows an enumerated type (say /enum e/) to be
compatible with /long/ or even /unsigned long long/. On the other hand,
subclause 6.2.1.1 states that the type converts to /int/ or /unsigned
int/ as part of the integral promotions. This produces the apparent
contradiction that two compatible types promote differently !
There are two alternative approaches to solving this.
(A) Replace subclause 6.5.2.2 paragraph 4 by:
Each enumerated type shall be compatible with one of the following
types:
signed char unsigned char
signed short unsigned short
signed int unsigned int
The choice of type is inplementation-defined, but shall be capable
of representing the values of all the members of the enumeration.
(B) Replace subclause 6.2.1.1 first paragraph by:
A /char/, a /short int/, or an /int/ bit-field, or their signed or
unsigned versions, may be used in an expression wherever an /int/ or
/unsigned int/ may be used. If an /int/ can represent all values of
the original type, the value is converted to an /int/; otherwise, it
is converted to an /unsigned int/. These are called the /integral
promotions/.
An enumeration type may be used in an expression wherever the type
that it is compatible with may be used. The integral promotions
cause the value to be converted in the same way as that compatible
type would be.
All other arithmetic types are unchanged by the integral promotions.
and in subclause 6.5.2.2, change the first sentence of paragraph 4 to:
Each enumerated type shall be compatible with some signed or
unsigned integral type.
[At present, enumerated types *are* integral types; the intent is
clearly to make them compatible with one of the 10 types named in
6.1.2.5.]
====
Item 13:
Delete subclause 6.5.7 paragraph 2:
There shall be no more initializers in an initializer list than
there are objects to be initialized.
Compare example 11.
Change paragraph 12 to read:
... the first named member of a union. ...
[This isn't strictly necessary, but makes things clearer.]
====
Item 14:
If implicit int is to be removed from the Standard, then there is no
longer a good rationale for allowing functions with an object return
type to execute a return statement without an expression.
Change subclause 6.6.6.4 as follows. Add to paragraph 1 (Constraints):
A /return/ statement without an expression shall only appear in a
function whose return type is /void/.
Delete from paragraph 2:
with and without expressions
Replace paragraph 4 by:
If the } that terminates a function is reached, and the value of the
function call is used by the caller, the behaviour is undefined.
Alternatively and preferably, delete paragraph 4 entirely and insert the
following paragraph in the Constraints, after paragraph 1:
In a function whose return type is not /void/, the last statement
before the terminating } shall have one of the following forms:
- a /return/ statement with an expression;
- a /goto/ statement;
- a block in which the last statement before the terminating } is,
recursively, one of these forms;
- an /if/ statement with an /else/, in which each substatement is,
recursively, one of these forms;
- a /switch/ statement which is not the smallest enclosing /switch/
or iteration statement of a /break/ statement, and in which the
switch body is, recursively, one of these forms;
- an iteration statement which is not the smallest enclosing
/switch/ or iteration statement of a /break/ statement, and in
which the controlling expression (/expression-2/ for a /for/
statement) is, or is replaced by, a non-zero constant expression.
and delete the last sentence of subclause 5.1.2.2.3.
If this latter text is not adopted, the last word of 5.1.2.2.3 should be
changed to "unspecified" - the concept of undefined value is carefully
avoided elsewhere.
--
Clive D.W. Feather | Associate Director | Director
Tel: +44 181 371 1138 | Demon Internet Ltd. | CityScape Internet Services Ltd.
Fax: +44 181 371 1150 | <clive@demon.net> | <cdwf@cityscape.co.uk>
Written on my laptop - please reply to the Reply-To address <clive@demon.net>