Defect Report #017
Submission Date: 10 Dec 92
Submittor: WG14
Source: X3J11/90-056 (Derek M. Jones)
Question 1
New-line in preprocessor directives
Subclause 5.1.1.2, page 5, line 37 says: ``Preprocessing
directives are executed and macro invocations are expanded.''
Subclause 6.8, page 86, lines 2-5 say: ``A preprocessing directive
... and is ended by the next new-line character.''
Subclause 6.8.3, page 89, lines 38-39 say: ``Within the sequence
of preprocessing tokens ... new-line is considered a normal white-space
character.''
These three statements are not sufficient to categorize the
following:
#define f(a,b) a+b
#if f(1,
2)
...
It should be defined whether the preprocessing directive
rule or macro expansion wins, i.e. is this code fragment legal or
illegal?
In translation phase 4 ``preprocessing directives are executed
and macro invocations expanded.''
Now do macro invocations get done first, followed by preprocessor
directives? Does the macro expander need to know that what it is
expanding forms a preprocessing directive?
Subclause 6.8, page 86, lines 2-5 suggest that the preprocessor
directive is examined to look for the new-line character. But how is it
examined? Obviously phases 1-3 happen during this examination. So why
shouldn't part of phase 4?
Correction
Add to subclause 6.8, page 86, line 5, (Description):
A new-line character ends the preprocessing directive even if it
occurs within what would otherwise be an invocation of a function-like
macro.
Question 2
Behavior if no function called main exists
According to subclause 5.1.2.2.1, page 6, it is implicitly
undefined behavior if the executable does not contain a function called
main.
It ought to be explicitly undefined if no
function called main exists in the executable.
Response
You are correct that it is implicitly undefined behavior if the
executable does not contain a function called main.
This was a conscious decision of the Committee.
There are many places in the C Standard that leave behavior
implicitly undefined. The Committee chose as a style for the C Standard
not to enumerate these places as explicitly undefined behavior. Rather,
subclause 3.16, page 3, lines 12-16 explicitly allow for implicitly
undefined behavior and explicitly give implicitly undefined behavior
equal status with other forms of undefined behavior.
Correction
Add to subclause G.2, page 200:
- A program contains no function called main
(5.1.2.2.1).
Question 3
Precedence of behaviors
Refer to subclause 6.1.2.6, page 25, lines 9-10 and subclause 6.5,
page 57, lines 20-21. The constructs covered by these sentences
overlap. The latter is a constraint while the former is undefined
behavior. In the overlapping case who wins?
Correction
In subclause 5.1.1.3, page 6, lines 15-17, change:
A conforming implementation shall produce at least one diagnostic
message (identified in an implementation-defined manner) for every
translation unit that contains a violation of any syntax rule or
constraint.
to:
A conforming implementation shall produce at least one diagnostic
message (identified in an implementation-defined manner) for every
translation unit that contains a violation of any syntax rule or
constraint, even if the behavior is also explicitly specified as
undefined or implementation-defined.
Add to subclause 5.1.1.3, page 6:
Example
An implementation shall issue a diagnostic for the translation
unit:
char i;
int i;
because in those cases where wording in this
International Standard describes the behavior for a construct as being
both a constraint error and resulting in undefined behavior, the
constraint error shall be diagnosed.
Question 4
Mapping of escape sequences
Refer to subclause 6.1.3.4, page 29, line 12 and line 16. Are
these values the values in the source or execution character set?
When subclause 6.1.3.4, page 29, line 24 says: ``The value of an
...,'' is this ``value'' the value in the source character set of the
escape sequence or the value of the mapped escape sequence? I would
have said that the ``value'' is the value in the execution environment
since in the source environment \x123 is part of a
token.
It might be argued that characters in the source character set do
not have values and thus no misinterpretation of ``value'' can occur.
Subclause 5.2.1, page 10, lines 25-26 refer to the value of a character
in the source basic character set.
Response
The values of octal or hexadecimal escape sequences are well
defined and not mapped. For instance, the value of the constant
'\x12' is always 18, while the value of the constant '\34'
is always 28.
The mapping described in subclause 6.1.3.4 on page 28, lines 35-39
only applies to members of the source character set, of which octal
and hexadecimal escape sequences clearly are not members.
Question 5
Example of value of character constants
Refer to subclause 6.1.3.4, page 29, lines 24-25 and page 30,
lines 9-10. Both of these statements cannot be true.
- If the constraint is violated, end of story. There is no
implementation-defined value.
- The implementation-defined behavior may be referring to the
mapping of the escape sequence to the basic character set, in which
case subclause 6.1.3.4, page 29, lines 24-25 should be changed to
mention that it will violate a constraint if the mapped value is outside
the range of representable values for the type unsigned char.
Response
The values of octal or hexadecimal escape sequences are well
defined and not mapped. For instance, the value of the constant
'\x123' has the value 291.
The mapping described in subclause 6.1.3.4 on page 28, lines 35-39
applies only to members of the source character set, of which octal
and hexadecimal escape sequences clearly are not members.
The constraint in subclause 6.1.3.4 on page 29, lines 24-25 will
be violated only if the implementation uses characters of eight bits.
The text of the example in subclause 6.1.3.4 on page 30, lines
8-10 is slightly opaque, but the parenthesized comment is meant to be
subject to the words ``Even if eight bits are used ...'' The value is
implementation-defined only in that the implementation specifies how
many bits are used for characters and whether type char
is signed or not.
This example could be worded a little more clearly to indicate
what is implementation-defined about the constant, and that it
``violates the above constraint'' only if eight bits are used for
objects that have type char, but we believe that this
interpretation is consistent with the intent of the Committee, and that
a reasonable reading of the standard supports this interpretation.
Question 6
register on aggregates
void f(void)
{
register union{int i;} v;
&v /* Constraint error */
&(v.i); /*
Constraint error or undefined? */
}
In subclause 6.3.3.2 on page 43, lines 37-38 in a
constraint clause, it says ``... and is not declared with the register
storage-class specifier.'' But in the above, the field i
is not declared with the register storage-class
specifier.
Footnote 58, on page 58, states that ``... the address of any part
of an object declared with storage-class specifier register
may not be computed ...'' Although the reference to this footnote is
in a constraints clause I think that it is still classed as undefined
behavior.
Various people have tried to find clauses in the standard that tie
the storage class of an aggregate to its members. I would not use the
standard to show this point. Rather I would use simple logic to show
that if an object has a given storage class then any of its constituent
parts must have the same storage class. Also the use of storage classes
on members is syntactically illegal.
The question is not whether such a construction is legal but the
status of its illegality. Is it a constraint error or undefined
behavior?
It might be argued that although register does
not appear on the field i, its presence is still
felt. I would point out that the standard does go to some pains to
state that in the case of const union{...} the
const does apply to the fields. The fact that there is no such
wording for register implies that register
does not follow the const rule.
Correction
Add to subclause 6.5.1, page 58 (Semantics):
If an aggregate or union object is declared with a storage-class
specifier other than typedef, the properties
resulting from the storage-class specifier, except with respect to
linkage, also apply to the members of the object, and so on recursively
for any aggregate or union member objects.
Question 7
Scope and uniqueness of size_t
Subclause 6.3.3.4 on page 45, lines 1-2 says: ``... and its type
(...) is size_t defined in the <stddef.h>
header.'' This line could be read as either of the following:
- ``... and its type is size_t which happens to be
defined in stddef.h.''
- ``... and its type is the size_t defined in
stddef.h.''
(It was probably intended as a helpful piece of information only.)
So what does the compiler do?
In (1) the compiler has to define a size_t in
some outer scope. This definition does not make size_t
visible, but gives a type to the return value of sizeof.
Now if the programmer defines a typedef making size_t
synonymous with float (say) then the compiler now has
to use this new type. This interpretation does not require the
programmer to include <stddef.h> in order to use
sizeof.
In (2) the compiler picks up the type size_t
from <stddef.h> (assuming that the user included
this header). Should the compiler give a diagnostic if this header was
not included and sizeof was used? A subsequent
typedef for size_t does not affect the type of the
result of sizeof.
These problems do not arise with int, et al.
because they are keywords. Thus ``typedef float int''
would give a syntax error and need not be considered semantically.
According to subclause 6.3.3.4, page 45, sizeof
has type size_t. What happens if the type of size_t
does not match what the compiler thinks is the type of sizeof?
Response
The relevant citations are subclause 6.3.3.4
The value of the result is implementation-defined, and its
type (an unsigned integral type) is size_t defined in
the <stddef.h> header.
and subclause 7.1.6
The types are ...
size_t
which is the unsigned integral type of the result of the sizeof
operator; ...
These sections, both separately and together, define the
relationship between the result type of sizeof and
the type size_t defined in stddef.h.
The result type of sizeof and the type size_t
defined in stddef.h are an unsigned integral type,
and size_t defined in <stddef.h>
is identical to the result type of sizeof. To
restate, in a conforming implementation, the result type of sizeof
will be the same as the type of size_t defined in
<stddef.h>.
Since these two types are the same, there need be no mechanism for
a compiler to discover the type of size_t defined in
<stddef.h>. A compiler's private knowledge of the
result type of sizeof is as good as stddef.h's
private knowledge of the type of
size_t.
Note that the result of sizeof has the same type
as not just any size_t, but the size_t
defined in <stddef.h>.
Question 8
Compatibility of pointer to void with storage
class
Refer to subclause 6.3.9, page 49, lines 24-25. Do these lines
make the following legal?
register void *p;
char *q;
if (p==q) /* legal */
...
The wording on line 25, ``... version of void;
or'' does not talk about the ``void type.'' This
sentence could be taken as simply referring to the occurrence of a
qualified or unqualified occurrence of void.
Should the wording on line 25 be changed to ``... version of the
type void; or'' and thus cause the storage class to be
ignored, or does the above example fall outside the scope of the
constraint?
Response
The relevant citation is subclause 6.3.9:
one operand is a pointer to an object or incomplete type
and the other is a pointer to a qualified or unqualified version of
void; or
The Committee believes that the current wording of the
standard is clear, and it is not changed in meaning by changing
``version of
void'' in the quoted section to ``version of the
void type.''
The standard uses the word ``void'' in two
contexts: the keyword itself and the type that the keyword names. The
context that the word is used in adequately distinguishes between the
two. In the section quoted, which discusses type compatibility, a
misreading of ``void'' as meaning the keyword quickly
results in nonsense.
As to the qualification discussed in the quoted passage, it is
type qualification, defined in subclause 6.5.3. The standard only uses
the words ``qualified'' and ``unqualified'' when discussing type
qualification and never uses them when discussing storage classes.
Thus, storage classes have no place in the discussion of the quoted
passage.
Question 9
Syntax of assignment expression
In subclause 6.3.16.1 on page 53, lines 31-32 there is a typo:
``... of the assignment expression ...'' should be ``... of the unary
expression ...''
In subclause 6.3.16 on page 53, lines 3-5 we have
assignment-expression:
...
unary-expression
assignment-operator assignment-expression
Now the string ``assignment-expression''
occurs twice.
The use of ``assignment expression'' in subclause 6.3.16 on page
53, line 12 refers to the first occurrence (the one to the left of the
colon).
We suggest changing the use of ``assignment expression'' in
subclause 6.3.16.1 on page 53, line 32 in order to prevent confusion.
The fact that any qualifier is kept actually makes more sense, since
this qualifier has to take part in any constraint checking.
Correction
Add to subclause 6.3.16.1, page 54, another Example:
In the fragment:
char c;
int i;
long l;
l = ( c = i );
the value of i is converted to the type of
the assignment-expression
c = i, that is, char type. The value
of the expression enclosed in parenthesis is then converted to the type
of the outer assignment-expression, that is, long
type.
Question 10
When is sizeof needed?
Refer to subclause 6.5.2.3, page 62, lines 28-29. When is the size
of an incomplete structure needed? An interpreter may not need the
size until run time, while some strictly typed memory architecture may
not even allow pointers to structures of unknown size.
In subclause 6.5.2.3, Footnote 63 starts off as an example. The
last sentence contains a ``shall.'' Does a violation of this ``shall''
constitute undefined behavior?
Even though an interpreter may not need the size of a structure
until run time its compiler still has to do some checking, i.e. an
unexecuted statement may contain sizeof an incomplete
type; even though the statement is unexecuted the constraint still has
to be detected.
Response
Whether the language processor is an interpreter or a true
compiler does not affect the language rules about when the size of an
object is needed. Both a compiler and an interpreter must act as if the
translation phases in subclause 5.1.1.2 were followed. This is a
requirement that an implementation act as if the entire program is
translated before the program's execution.
The ``shall'' in Footnote 63 in subclause 6.5.2.3 carries no
special meaning: this footnote, like all other footnotes in the
standard, is provided to emphasize the consequences of the rules in the
standard. The footnote is not part of the standard.
The Committee believes that a careful reading of the standard
shows all of the places that the size of an object is needed, and that
the translation phases prevent those requirements from being relaxed by
an implementation.
Question 11
Clarification of incomplete struct declaration
Referring to subclause 6.5.2.3, page 62:
struct t;
struct t; /* Is this undefined?
*/
People seem to think that the above is undefined.
The problem arises because no rules exist for compatibility of
incomplete structures or unions.
Response
The proposed example is valid. Nothing in the standard prohibits
it.
The relevant citation is subclause 6.5.2.3 Semantics, paragraph 2:
A declaration of the form
struct-or-union identifier ;
specifies a structure or union type and declares a tag, both
visible only within the scope in which the declaration occurs. It
specifies a new type distinct from any type with the same tag in an
enclosing scope (if any).
Question 12
Ambiguous parsing of typedefs in prototypes
On page 67 in subclause 6.5.4.3, an ambiguity needs resolving in
the parsing of the following:
- int x(T (U));
- int x(T (U (int a, char b)));
In (a) U is the type of the parameter to a
function returning type T. From subclause 6.5.4.3,
page 68, line 2:
In a parameter declaration, a single typedef name in
parentheses is taken to be an abstract declarator that specifies a
function with a single parameter, not as redundant parentheses around
the identifier for a declarator.
Thus in the case of (b):
- U could be a redundantly parenthesized name of a
function which takes a parameter-type-list
and returns type T, or
- U could be the type returned by a function which
takes a
parameter-type-list, which in turn is the
single parameter of a function returning type T.
Response
See Defect Report #009, Question 1 for
a clarifying correction in this area.
Question 13
Compatibility of functions with register on
parameters
Reference subclause 6.5.4.3, page 67.
f1(int);
f1(register int a) /* Is this function
compatible with the above?
*/
{
}
Subclause 6.5.4.3, page 68, lines 5-7 were presumably
intended to make sure that the register storage class
got kept in the case of a definition so that the appropriate
constraints applied, i.e., it is not allowed to take its address, etc.
But the further implication of the wording is that the occurrence of
register lingers on for other uses - but there are
no other uses.
Suggest a clarification on this point.
Response
The function is compatible. Storage class is not part of the type.
The relevant citation, as given, is subclause 6.5.4.3, page 68,
lines 5-7, but it does not imply any ``other uses.''
Question 14
const void type as a parameter
Refer to subclause 6.5.4.3, page 67, line 37. f(const
void) should be explicitly undefined; also f(register
void), f(volatile void), and combinations
thereof.
Correction
Add to subclause G.2, page 201:
- A storage-class specifier or type qualifier modifies the
keyword
void as a function parameter type list (6.5.4.3).
Question 15
Ordering of conversion of arrays to pointers
In subclause 6.5.4.3 on page 68, line 22 there is a sentence in
parentheses. Does the sentence refer to the whole paragraph or just the
preceding sentence?
int f(int a[4]);
int f(int a[5]);
int f(int *a);
- It refers to the whole paragraph. This makes all of the above
three declarations compatible.
- It does not refer to the whole paragraph. This makes all three
declarations incompatible.
Response
Regarding page 68, line 22: There are two sentences in
parentheses. They apply to the entire paragraph. The declarations are
all compatible. (See Defect Report #013, Question 1 for a clarifying
correction in this area.)
Question 16
Pointer to multidimensional array
Given the declaration:
char a[3][4], (*p)[4]=a[1];
Does the behavior become undefined when:
- p no longer points within the slice of the
array, or
- p no longer points within the object a?
This case should be explicitly stated.
Arguments for/against:
The standard refers to a pointed-to object. There does not appear
to be any concept of a slice of an array being an independent object.
Response
For an array of arrays, the permitted pointer arithmetic in
subclause 6.3.6, page 47, lines 12-40 is to be understood by
interpreting the use of the word ``object'' as denoting the specific
object determined directly by the pointer's type and value, not
other objects related to that one by contiguity. Therefore, if an
expression exceeds these permissions, the behavior is undefined. For
example, the following code has undefined behavior:
int a[4][5];
a[1][7] = 0; /* undefined */
Some conforming implementations may choose to diagnose an
``array bounds violation,'' while others may choose to interpret such
attempted accesses successfully with the ``obvious'' extended
semantics.
Correction
Add to subclause G.2, page 201:
- An array subscript is out of range, even if an object is
apparently accessible with the given subscript (as in the lvalue
expression a[1][7] given the declaration int
a[4][5]) (6.3.6).
Question 17
Initialization of unions with unnamed members
Subclause 6.5.7 on page 71, line 39 says: ``All unnamed structure
or union members are ignored ...'' On page 72, lines 22-23, it says:
``... for the first member of the union.'' Subclause 6.5.2.1, page 60,
line 40 and Footnote 60 say that a field with no declarator is a
member.
union {
int :3;
float f;} u = {3.4};
Should page 72 be changed to refer to the first named
member or is the initialization of a union whose first member is
unnamed illegal?
It has been suggested that the situation described above is
implicitly undefined.
I think that it is a straightforward ambiguity that needs
resolution one way or the other.
Correction
In subclause 6.5.7, page 71, line 39, change:
All unnamed structure or union members are ignored during
initialization.
to:
Except where explicitly stated otherwise, for the purposes of this
subclause unnamed members of objects of structure and union type do
not participate in initialization. Unnamed members of structure objects
have indeterminate value even after initialization. A union object
containing only unnamed members has indeterminate value even after
initialization.
In subclause 6.5.7, page 72, line 11, change:
The initial value of the object is that of the expression.
to:
The initial value of the object, including unnamed members, is
that of the expression.
Question 18
Compatibility of functions with void and no
prototype
f2(void);
f2(); /* Is this function compatible
with the one above? */
Now subclause 6.5.4.3, page 68, line 1 says that the
first declaration of f2 specifies that the function
has no parameters.
No rules are given in the subsequent paragraphs to say that a
function declaration with a parameter type list, with no parameters, is
compatible with a function declaration with an empty parameter list.
If we treat the void as a single parameter then
page 68, lines 14-18 would make the above two functions incompatible.
void is not compatible with any default promotions.
subclause 6.5.4.3, page 68, lines 18-22 cover the case for declaration
and definition.
Thus I think that in the above example the behavior is implicitly
undefined.
Response
Subclause 6.5.4.3, page 67, line 37 and page 68, line 1 state,
``The special case of void as the only item in the
list specifies that the function has no parameters.'' Therefore, in the
case of
f2(void); there are no parameters just as
there are none for f2();. Since both functions have
the same return type, these declarations are compatible.
Question 19
Order of evaluation of macros
Refer to subclause 6.8.3, page 89. In:
#define f(a) a*g
#define g(a) f(a)
f(2)(9)
it should be defined whether this results in:
- 2*f(9)
or
- 2*9*g
X3J11 previously said, ``The behavior in this case could have been
specified, but the Committee has decided more than once not to do so.
[They] do not wish to promote this sort of macro replacement usage.''
I interpret this as saying, in other words, ``If we don't define
the behavior nobody will use it.'' Does anybody think this position is
unusual?
People seem to agree that the behavior is ambiguous in this case.
Should we specify this case as undefined behavior?
Response
If a fully expanded macro replacement list contains a
function-like macro name as its last preprocessing token, it is
unspecified whether this macro name may be subsequently replaced. If
the behavior of the program depends upon this unspecified behavior,
then the behavior is undefined.
For example, given the definitions:
#define f(a) a*g
#define g(a) f(a)
the invocation:
f(2)(9)
results in undefined behavior. Among the possible behaviors are
the generation of the preprocessing tokens:
2*f(9)
and
2*9*g
Correction
Add to subclause G.2, page 202:
- A fully expanded macro replacement list contains a
function-like macro name as its last preprocessing token (6.8.3).
Question 20
Scope of macro parameters
Refer to subclause 6.8.3 on page 89, line 16; the scope of macro
parameters should be defined in the section on scope.
The idea is to enable all references to the scope of names to be
under one heading. This is not really a significant issue.
Response
Subclause 6.1.2 on page 20, line 5, states ``Macro names and macro
parameters are not considered further here.'' This approach was
intentionally adopted to avoid explicitly having to mention exceptions
of using identifiers, for example in the sections on scope, linkage,
name spaces, and storage durations, none of which applies to macros.
The proposed change does not clarify the standard and may even
obscure it.
Question 21
Self references in translation phase 4
The following queries arise because of the imprecise way in which
phase 4 interacts with itself. While processing a token within phase 4
it is sometime necessary to get the following tokens from the input,
i.e. reading the arguments to a function-like macro. But when getting
these tokens it is not clear how many phases operate on them:
- Do the following tokens only get processed by phases 1-3?
- Do the following tokens get processed by phases 1-4?
When an identifier declared as a function-like macro is
encountered, how hard should an implementation try to locate the
opening/closing parentheses?
In:
#define lparen (
#define f_m(a) a
f_m lparen "abc" )
should the object-like macro be expanded while searching
for an opening parenthesis? Or does the lack of a readily available
left parenthesis indicate that the macro should not be expanded?
Subclause 6.8.3, on page 89, lines 34-35 says ``... followed by a
( as the next preprocessing token ...'' This sentence
does not help because in translation phase 4 all tokens are
preprocessing tokens. They don't get converted to ``real'' tokens until
phase 7. Thus it cannot be argued that lparen is not
correct in this situation, because its result is a preprocessing token.
In:
#define i(x) 3
#define a i(yz
#define b )
a b )
/* goes to 3) or 3 */
does b get expanded to complete the
call i(yz, or does the parenthesis to its right get
used?
Response
Concerning the first example:
#define lparen (
#define f_m(a) a
f_m lparen "abc" )
According to subclause 5.1.1.2 Translation phases,
page 5, lines 25-39, the translation phases 1-3 do not cause macros to
be expanded. Phase 4 does expand. To apply subclause 6.8.3 Macro
replacement page 89, lines 34-35 to the example: Since lparen
is not ( in ``f_m lparen "abc" ),''
this construct is not recognized as a function-like macro invocation.
Therefore the example expands to
f_m("abc")
The same principle applies to the second example:
#define i(x) 3
#define a i(yz
#define b )
a b )
/* expands via the following stages: */
i(yz b ) /* ) delimits the argument list before
b is expanded
*/
i([yz ) ])
3
This is how we interpret subclause 6.8.3, page 89, lines
36-38: The sequence of preprocessing tokens is terminated by the
right-parenthesis preprocessing token.
Question 22
Gluing during rescan
Reference: subclause 6.8.3.3, page 90. Does the rescan of a macro
invocation also perform gluing?
#define hash_hash # ## #
#define mkstr(a) # a
#define
in_between(a) mkstr(a)
#define join(c, d) in_between(c hash_hash d)
char p[2] = join(x, y);
Is the above legal? Does join expand to "xy"
or "x ## y"?
It all depends on the wording in subclause 6.8.3.3 on page 90,
lines 39-40. Does the wording ``... before the replacement list is
reexamined ...'' mean before being reexamined for the first time only,
or before being reexamined on every rescan?
This rather perverse macro expansion is only made possible because
the constraints on the use of # refer to
function-like macros only. If this constraint were extended to cover
object-like macros the whole question goes away.
Dave Prosser says that the intent was to produce "x ## y".
My reading is that the result should be "xy". I
cannot see any rule that says a created ## should not
be processed appropriately. The standard does say in subclause 6.8.3.3,
page 90, line 40 ``... each instance of a ## ...''
The reason I ask if the above is legal is that the order of
evaluation of # and ## is not
defined. Thus if # is performed first the result is
very different than if ## goes first.
Correction
Add to subclause 6.8.3.3, page 90:
Example
#define hash_hash # ## #
#define mkstr(a) # a
#define
in_between(a) mkstr(a)
#define join(c, d) in_between(c hash_hash d)
char p[] = join(x, y); /* equivalent to char p[] = "x ##
y";*/
The expansion produces, at various stages:
join(x, y)
in_between(x hash_hash y)
in_between(x ##
y)
mkstr(x ## y)
"x ## y"
In other words, expanding hash_hash
produces a new token, consisting of two adjacent sharp signs, but this
new token is not the catenation operator.
Question 23
How long does blue paint persist?
Consider the following code:
#define a(x) b
#define b(x) x
a(a)(a)(a)
The macro replacement for a(a) results
in b.
First replacement buffer: b
Remaining tokens: (a)(a)
Inside the first replacement buffer, no further nested
replacements will recognize the macro name ``a.'' The
name ``a'' is painted blue.
The first replacement buffer is rescanned not by itself, but along
with the rest of the source program's tokens. ``b(a)''
also causes macro replacement and becomes ``a.''
Second replacement buffer: a
Remaining tokens: (a)
The second replacement buffer is rescanned not by itself, but
along with the rest of the source program's tokens.
The ``a'' in the second replacement buffer did
not come from the first replacement buffer. It came from three of the
remaining tokens which were in the source file following the first
replacement buffer. Is this ``a'' part of a nested
replacement? Is it still painted blue?
Note that there are many ``paths'' that can be taken for a
possible macro name to travel from a preprocessing token (outside the
replacement buffer) to one that is inside the replacement buffer. When
do they stop getting painted blue? If either too early or too late,
they cause very surprising results.
Given the amount of discussion involving macro expansion that uses
the concept of ``blue paint,'' why doesn't the standard tell the
reader about this idea?
Everybody seems to agree that the above is undefined. Does anybody
have a set of words to make this and other cases explicitly undefined?
Response
The reference is to subclause 6.8.3.4, page 91.
#define a(x) b
#define b(x) x
a(a)(a)(a) /*
may expand as follows: */
b(a)(a)
a'(a) or
a(a)
a(a) or b
/* a'
indicates the symbol a marked for non-replacement */
The Committee addressed this issue explicitly in
previous deliberations and decided to say nothing about the situation,
understanding that behavior in such cases would be undefined.
The result, as with other examples, is intentionally left
undefined.
Question 24
Improve English
Just a tidy up. Change subclause 7.1.2, page 96, line 33 from ``if
the identifier'' to ``if an identifier.''
Correction
In subclause 7.1.2, page 96, lines 32-33, change:
However, if the identifier is declared or defined in more than one
header,
to:
However, if an identifier is declared or defined in more than one
header,
Question 25
``Must'' in footnotes
This change is not essential since footnotes have no status. But
this change would cut down the number of occurrences of ``shall''
synonyms used where ``shall'' itself could have be used.
Response
The standard is clear enough as is.
Question 26
Implicit initialization of unions with unnamed members
Are unnamed union members required to be initialized?
Response
See Defect Report #017, Question 17 for a clarifying correction in
this area.
Question 27
g conversions
Subclause 7.9.6.1 says on page 132, lines 42: ``For g
and
G conversions, trailing zeros will not be
removed ...,'' whereas on page 133, lines 37-38 it says: ``Trailing
zeros are removed ...''
It has been suggested that the italics on page 132, lines 42 gives
this rule precedence. I don't mind which rule wins as long as the text
says so. Do we add text to describe the italics rule or change the
conflicting lines?
Response
In the collision between the description of the #
flag and the
g and G conversion specifiers to
fprintf, which takes precedence?
The # flag takes precedence. Subclause 7.9.6.1,
page 132, line 1 says, ``Zero or more flags (in any order) ...
modify the meaning of the conversion specification.''
Question 28
Ordering of conditions on return
In subclause 7.9.9.1, subclause 7.9.9.3, and subclause 7.9.9.4,
the words are ``returns ... and stores an implementation-defined
positive value in errno.'' This is a strange order of
operations - shouldn't the wording be reversed?
Response
No. In subclause 7.9.9.1, subclause 7.9.9.3, and subclause
7.9.9.4, the words ``returns ... and stores an implementation-defined
positive value in errno'' do not imply any temporal
ordering. There are implementations that may perform these operations
in either order and they still meet the standard.
Question 29
Conversion failure and longest matches
Consider 1.2e+4 with field width of 5. Is it
input item 1.2e+ that gives a conversion failure?
What is the ordering between building input items and converting them?
Do they run in parallel, or sequential?
Refer to subclause 7.9.6.2 The fscanf function,
page 135, lines 31-33 concerning the longest matching sequence, and
subclause 7.9.6.2, page 137, lines 15-16 concerning a conflicting input
character.
For 1.2e-x, is 1.2 or 1.2e-
read?
The above questions all come about because of page 137, line 15:
``If conversion terminates ...'' In this context the use of the word
``conversion'' could be referring to the process of turning a sequence
of characters into numeric form. I believe what was intended was ``If a
conversion specifier terminates ...''
Response
The relevant citations are subclause 7.9.6.2, page 137, lines
15-16:
If conversion terminates on a conflicting input character, the
offending input character is left unread in the input stream.
and subclause 7.9.6.2, page 135, lines 31-33:
An input item is defined as the longest matching sequence of
input characters, unless that exceeds a specified field width, in which
case it is the initial subsequence of that length in the sequence.
and subclause 7.9.6.2, page 135, lines 38-40:
If the input item is not a matching sequence, the execution of
the directive fails: this condition is a matching failure.
The ``conversion'' in the first quoted passage is the process of
both forming an input item and converting it as specified by the
conversion specifier.
About your example: If the characters available for input are ``
1.2e+4'' and input is performed using a ``%5e,''
then the input item is ``1.2e+'' as defined by the
second passage quoted above. That input item is not a matching
sequence, but only an initial subsequence that fails to be a matching
sequence in its own right. Under the rules of the third quoted passage,
this is a matching failure.
Note that in this case, no characters were pushed back onto the
input stream. There was no ``conflicting input character'' that
terminated the field, and so the first quoted passage does not apply.
See the Correction made in response to Defect Report #022,
Question 1, for additional clarification.
Question 30
Successful call to ftell or fgetpos
In subclause 7.9.9.2 on page 145, lines 39-40, ``... a value
returned by an earlier call to the ftell function
...'' should actually read ``... a value returned by an earlier
successful call ...'' Similarly for subclause 7.9.9.3.
Correction
In subclause 7.9.9.2, page 145, lines 39-40, change:
a value returned by an earlier call to the ftell
function
to:
a value returned by an earlier successful call to the ftell
function
In subclause 7.9.9.3, page 146, lines 10-11, change:
a value obtained from an earlier call to the fgetpos
function
to:
a value obtained from an earlier successful call to the fgetpos
function
Question 31
Size in bytes
References to the size of an object in other parts of the standard
specify that size is measured in bytes. The following lines do not
follow this convention: subclause 7.10.3.1 on page 154, lines 26-27 and
subclause 7.10.3.3 on page 155, line 8.
Response
There are numerous places in the standard where ``size in bytes''
is used, and numerous places where ``size'' alone is used. The
Committee does not feel that any of these places need fixing - the
meaning is everywhere clear, especially since for sizeof
in subclause 6.3.3.4 size is specifically mentioned in terms of bytes.
Question 32
char parameters to strcmp and
strncmp
Refer to subclause 7.11.4, page 164. If char is
signed then
char * cannot be interpreted as pointing to unsigned
char. The required cast may give undefined results. This
applies to strcmp and strncmp.
Response
strcmp can compare two char strings,
even though the representation of char may be signed,
because subclause 7.11.4, page 164, line 7 says that the interpretation
of bytes is done as if each byte were accessed as an unsigned
char. We believe the standard is clear.
Question 33
Different length strings
Refer to subclause 7.11.4, page 164, lines 5-7. What about strings
of different length?
Perhaps the fact that the terminating null character takes part in
the comparison ought to be mentioned.
Response
Subclause 7.1.1 on page 96, lines 4-5 says that a string includes
the terminating null character. Therefore this character takes part in
the comparison. The standard is clear.
Question 34
Calls to strtok
In subclause 7.11.5.8 on page 167, line 36, ``... first call ...''
should read ``... all calls ...''
I think that the current wording causes confusion. The first call
is the one that takes a non-NULL ``s1''
parameter. However, the discussion from line 36 onwards is describing
the behavior for all calls.
Response
The Committee felt that the suggested wording for the strtok
function description is not an improvement. The existing wording is
clear as written.
Question 35
When is a physical source line created?
Is the output or input to translation phase 1 a physical source
line?
Response
The use of the term ``physical source line'' occurs only in the
description of the phases of translation (subclause 5.1.1.2) and the
question of whether the input or output of phase 1 consists of physical
source lines does not matter.
Question 36
Qualifiers on function return type
Refer to subclause 6.6.6.4, page 80, line 24-25: ``... whose
return type is void.''
The behavior of a type qualifier on a function return is
explicitly undefined, according to subclause 6.5.3, page 64, lines
24-25.
This creates a loophole.
An implementation that supports type qualifiers on function return
types is not required to flag the constraint given on page 80.
Response
A Constraint on subclause 6.7.1 says ``The return type of a
function shall be void or an object type other than
array.''
Question 37
Function result type
Refer to subclause 6.3.2.2, page 40, line 35. The result type of a
function call is not defined.
Correction
In subclause 6.3.2.2, page 40, line 35, change:
The value of the function call expression is specified in 6.6.6.4.
to:
If the expression that denotes the called function has type
pointer to function returning an object type, the function call
expression has the same type as that object type, and has the value
determined as specified in 6.6.6.4. Otherwise, the function call has
type void.
Question 38
What is an iteration control structure or selection control
structure?
An ``iteration control structure,'' a term used in subclause
5.2.4.1 Translation limits on page 13, line 1, is not defined
by the standard.
Is it:
- A for loop header excluding its body, e.g.
for (;;),
or
- A for loop header plus its body, e.g. for
(;;) {}?
Does it make a difference if the compound statement is a simple
statement without the braces?
Correction
In subclause 5.2.4.1, page 13, lines 1-2, change:
- 15 nested levels of compound statements, iteration control
structures, and selection control structures
to:
- 15 nested levels of compound statements, iteration statements,
and selection statements
Question 39
Header name tokenization
There is an inconsistency between subclause 6.1.7, page 33, line 8
and the description of the creation of header name preprocessing
tokens.
The ``shall'' on page 32, line 33 does not limit the creation of
header name preprocessing tokens to within #include
directives. It simply states that they would cause a constraint error
in this context.
Subclause 6.1.7, page 33, line 8 should read {0x3}{<1/a.h>}{1e2}, or extra text needs
to be added to subclause 6.1.7.
I have not met anybody who expects if (a<b || c>d)
to parse as {if} {(} {a}
{<b || c>} {d} {)}.
Correction
Add to subclause 6.1, page 18 (Semantics):
A header name preprocessing token is only recognized within a
#include preprocessing directive, and within such a directive,
a sequence of characters that could be either a header name or a string
literal is recognized as the former.
Add to subclause 6.1.2, page 20 (Semantics):
When preprocessing tokens are converted to tokens during
translation phase 7, if a preprocessing token could be converted to
either a keyword or an identifier, it is converted to a keyword.
In subclause 6.1.7, page 32, lines 32-34, delete:
Constraint
Header name preprocessing tokens shall only appear within a
#include preprocessing directive.
Add to subclause 6.1.7, page 32 (Semantics):
A header name preprocessing token is recognized only within a
#include preprocessing directive.
Previous Defect Report
< - > Next Defect Report