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.
  1. If the constraint is violated, end of story. There is no implementation-defined value.
  2. 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:
  1. ``... and its type is size_t which happens to be defined in stddef.h.''
  2. ``... 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:
  1. int x(T (U));
  2. 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):
  1. U could be a redundantly parenthesized name of a function which takes a parameter-type-list and returns type T, or
  2. 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);
  1. It refers to the whole paragraph. This makes all of the above three declarations compatible.
  2. 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:
  1. p no longer points within the slice of the array, or
  2. 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:
  1. 2*f(9)
    or
  2. 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:
  1. Do the following tokens only get processed by phases 1-3?
  2. 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:
  1. A for loop header excluding its body, e.g. for (;;),
    or
  2. 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