When the ANSI C standard X3.159-1989 was adopted as an International
Standard in 1990, not only did "sections" turn into "clauses" and
"subclauses" (and incidentally get renumbered), but there also suddenly
appeared a protocol for gradually changing and updating the standard in
reaction to complaints by its users, something ANSI had not provided for.
Thus, the letters that had started out as as humble Requests For
Interpretation to ANSI X3J11 - many of which didn't want the standard
explained, but changed - overnight became Defect Reports to ISO/IEC
committee JTC1/SC22/WG14.
Four years later, the first batch of 59 Defect Reports has received
answers, some of which recommended changes to the text of the standard.
These questions and answers are assembled as Record of Response
Number 1, and those which recommend changes are also put together as
Technical Corrigendum Number 1. After being reviewed and voted
on by the member bodies such as ANSI and BSI, both documents have been
formally accepted: the C standard has changed !
TC1 is the result of many people's work. There are a large number
of sources for the original Defect Reports (and often a single name
hides many others). The answers were discussed at several
WG14 and X3J11 meetings, sometimes received further, more informal,
commentary from other experts, and underwent a final review by
Clive Feather
and Doug Gwyn.
However, if any single person should take credit for TC1, it is P.J. Plauger,
who assembled and edited it, and generally drove the process to completion.
This HTML document is not Technical Corrigendum Number 1.
With very few exceptions, ISO documents are sold by ISO and their national
member organizations to finance their work. Instead, this is a
collection of the Normative Changes contained within the
Technical Corrigendum. It contains all the actual changes
to the standard, but not the questions and explanations surrounding them.
The changes are listed in the order they occur within the standard;
see the end of the document for a permuted index of
topics.
- 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.
- 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
- 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.2.2, page 21, change:
-
If the declaration of an identifier for an object or a function
contains the storage-class specifier
extern
, the identifier has the
same linkage as any visible declaration of the identifier with file
scope. If there is no visible declaration with file scope, the
identifier has external linkage.
- to:
-
For an identifier declared with the storage-class specifier
extern
in a
scope in which a prior declaration of that identifier is visible*,
if the prior declaration specifies internal or external linkage,
the linkage of the identifier at the latter declaration becomes the
linkage specified at the prior declaration. If no prior declaration
is visible, or if the prior declaration specifies no linkage, then
the identifier has external linkage.
_______________________________________________________________
* As specified in 6.1.2.1, the latter declaration might hide the
prior declaration.
- In subclause 6.1.2.6, page 25, lines 19-20, change:
-
For an identifier with external or internal linkage declared in the
same scope as another declaration for that identifier, the type of
the identifier becomes the composite type.
- to:
-
For an identifier with internal or external linkage declared in a
scope in which a prior declaration of that identifier is visible*,
if the prior declaration specifies internal or external linkage,
the type of the identifier at the latter declaration becomes the
composite type.
_______________________________________________________________
* As specified in 6.1.2.1, the latter declaration might hide the
prior declaration.
- 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.
- In subclause 6.3, page 38, lines 18-21, change:
-
An object shall have its stored value accessed only by an lvalue
expression that has one of the following types:[36]
- the declared type of the object,
- a qualified version of the declared type of the object,
- to:
-
An object shall have its stored value accessed only by an lvalue
expression that has one of the following types:[36]
- a type compatible with the declared type of the object,
- a qualified version of a type compatible with the declared type of
the object,
- 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
.
- 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.
- 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.
- In subclause 6.5.2.3, page 62, line 27, change:
-
occurs prior to the declaration that defines the content
- to:
-
occurs prior to the
}
following the
struct-declaration-list that defines the content
- Add to subclause 6.5.2.3, page 63, another Example:
-
An enumeration type is compatible with some integral type.
An implementation may delay the choice of which integral
type until all enumeration constants have been seen. Thus in:
enum f { c = sizeof(enum f) };
the behavior is undefined since the size of the respective enumeration
type is not necessarily known when sizeof
is encountered.
- In subclause 6.5.4.3, page 68, lines 2-4, replace:
-
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.
- with:
-
If, in a parameter declaration, an identifier can be treated as a
typedef name or as a parameter name, it shall be taken as a typedef
name.
- In subclause 6.5.4.3, page 68, lines 22-25, change:
-
(For each parameter declared with function or array type, its type
for these comparisons is the one that results from conversion to a
pointer type, as in 6.7.1. For each parameter declared with qualified
type, its type for these comparisons is the unqualified version of its
declared type.)
- to:
-
(In the determination of type compatibility and of a composite type,
each parameter declared with function or array type is taken as
having the type that results from conversion to a pointer type, as
in 6.7.1, and each parameter declared with qualified type is taken
as having the unqualified version of its declared type.)
- 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 71, line 41 through page 72, line 2, change:
-
If an object that has static storage duration is not initialized
explicitly, it is initialized implicitly as if every member that has
arithmetic type were assigned 0 and every member that has pointer type
were assigned a null pointer constant.
- to:
-
If an object that has static storage duration is not initialized
explicitly, then:
- if it has pointer type, it is initialized to a null pointer;
- if it has arithmetic type, it is initialized to zero;
- if it is an aggregate, every member is initialized (recursively)
according to these rules;
- if it is a union, the first named member is initialized (recursively)
according to these rules.
- 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.
- In subclause 6.6.6.4, page 80, lines 30-32, replace:
-
If the expression has a type different from that of the function in
which it appears, it is converted as if it were assigned to an
object of that type.
- with:
-
If the expression has a type different from the return type of the
function in which it appears, the value is converted as if by assignment
to an object having the return type of the function*.
_______________________________________________________________
* The return
statement is not an assignment. The
overlap restriction in subclause 6.3.16.1 does not apply to the case
of function return.
- Add to subclause 6.6.6.4, page 80:
-
Example
In:
struct s {double i;} f(void);
union {struct {int f1;
struct s f2;} u1;
struct {struct s f3;
int f4;} u2;
} g;
struct s f(void)
{
return g.u1.f2;
}
/* ... */
g.u2.f3 = f();
the behavior is defined.
- Add to subclause 6.7.2, page 84, a second Example:
-
If at the end of the translation unit containing
int i[];
the array i
still has incomplete type, the array is assumed
to have one element. This element is initialized to zero on program
startup.
- 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.
- Add to subclause 6.8, page 86 (Constraints):
-
In the definition of an object-like macro, if the first character of a
replacement list is not a character required by subclause 5.2.1, then
there shall be white-space separation between the identifier and the
replacement list.*
_______________________________________________________________
* This allows an implementation to choose to interpret the directive:
#define THIS$AND$THAT(a,b) ((a) + (b))
as defining a function-like macro THIS$AND$THAT
, rather than an
object-like macro THIS
. Whichever choice it makes, it must also
issue a diagnostic.
- 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.
- 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,
- Add to subclause 7.1.2, page 96 (before Forward references):
-
Any definition of an object-like macro described in this clause shall
expand to code that is fully protected by parentheses where necessary,
so that it groups in an arbitrary expression as if it were a single
identifier.
- In subclause 7.7, page 120, lines 14-16, change:
-
and the following, each of which expands to a positive integral
constant expression that is the signal number corresponding to the
specified condition:
- to:
-
and the following, which expand to positive integral constant expressions
with distinct values that are the signal numbers, each corresponding to
the specified condition:
- In subclause 7.9.6.1, page 132, lines 37-38, change:
-
For
o
conversion, it increases the precision to force the first
digit of the result to be a zero.
- to:
-
For
o
conversion, it increases the precision, if and only if
necessary, to force the first digit of the result to be a zero.
- In subclause 7.9.6.2, page 135, lines 31-33,
change:
-
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.
- to:
-
An input item is defined as the longest sequence of input characters
which does not exceed any specified field width and which is, or is
a prefix of, a matching input sequence.
- In subclause 7.9.6.2, page 137, delete:
-
If conversion terminates on a conflicting input character, the
offending input character is left unread in the input stream.
- Add to subclause 7.9.6.2, page 137:
-
If conversion terminates on a conflicting input character, the
offending input character is left unread in the input stream*.
_______________________________________________________________
* fscanf
pushes back at most one input character onto the input
stream. Therefore, some sequences that are acceptable to
strtod
, strtol
, or strtoul
are unacceptable to fscanf
.
- Add to subclause 7.9.6.2, page 137, line 4 (the
n
conversion specifier): -
No argument is converted, but one is consumed. If the conversion
specification with this conversion specifier is not one of
%n
, %ln
,
or %hn
, the behavior is undefined.
- Add to subclause 7.9.6.2, page 138, another Example:
-
In:
#include <stdio.h>
/* ... */
int d1, d2, n1, n2, i;
i = sscanf("123", "%d%n%n%d", &d1, &n1, &n2, &d2);
the value 123 is assigned to d1
and the value 3 to n1
.
Because %n
can never get an input failure the value of 3 is
also assigned to n2
. The value of d2
is not affected.
The value 3 is assigned to i
.
- 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
- Add to subclause 7.11.1, page 162:
-
Where an argument declared as
size_t n
specifies the length of the
array for a function, n
can have the value zero on a call to that
function. Unless explicitly stated otherwise in the description of a
particular function in this subclause, pointer arguments on such a call
must still have valid values, as described in subclause 7.1.7. On such
a call, a function that locates a character finds no occurrence, a
function that compares two character sequences returns zero, and a
function that copies characters copies zero characters.
- In subclause 7.12.2.3, page 172, line 16,
change:
-
if (mktime(&time_str) == -1)
- to:
-
if (mktime(&time_str) == (time_t)-1)
- Add to subclause G.2, page 200:
-
- A program contains no function called
main
(5.1.2.2.1).
- Add to subclause G.2, page 200:
-
- A storage-class specifier or type qualifier modifies the keyword
void
as a function parameter type list (6.5.4.3).
- 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).
- 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).
- Add to subclause G.2, page 203:
-
- A call to a library function exceeds an environmental limit
(7.9.2, 7.9.3, 7.9.4.4, 7.9.6.1, 7.10.2.1).
- In the index, page 217, change:
-
static
storage-class specifier, 3.1.2.2, 6.1.2.4, 6.5.1, 6.7
- to:
-
static
storage-class specifier, 6.1.2.2, 6.1.2.4, 6.5.1, 6.7
(This index was compiled to facilitate hypertext access to the changes that are
relevant to a given subject; it is not part of any standard document.)
- access
-
of an object's stored value,
legal types for lvalue used to
- array
-
type completion through
default initialization
struct, and union: see aggregate
and union types
subscript out of range, even if
apparently accessible
- aggregate and union types,
-
effects of storage-class specifiers
other than
typedef
on
recursive initialization of
- assignment
-
type, example for conversion to
of function result to storage
overlapping its source
- behavior, undefined
-
see undefined behavior
- compatible type
-
of functions with parameters that have function,
array, or qualified type
use for accessing an object's stored value,
lvalue having
- composite type
-
of functions with parameters that have
function, array, or qualified type
of redeclared identifiers with
internal or external linkage
- constraint,
-
on header name tokens only in
#include
directives, deleted
on white space between object-like
macro name and special character, added
violation, precedence
over undefined behavior
- control structure,
-
iteration or selection
- conversion
-
of array and function type parameters to
pointers
of preprocessing tokens to keywords or
identifiers
- declaration
-
of already visible identifiers with internal or
external linkage, resulting type
that defines the contents, occurrence of
struct tag prior to
- diagnostic message
-
for constraint violation, even
when behavior is undefined
- elements,
-
effects of storage-class specifier on array
recursive initialization of array
- enum,
-
unknown compatible integral type before
all constants have been seen
- environmental limit,
-
calls to library functions that exceed
- example
-
for code that is both undefined
and violates a constraint
for completion of array type through
default initialization
for conversion to type of assignment
expression
for delayed choice of the integral type
that is compatible with an enum
for ##
that is not
a catenation operator
for legal assignment of function result to
overlapping object
for use of %n
specification in
fscanf
- extern,
-
linkage of identifiers with internal or
external linkage that are redeclared as
type of identifiers with internal or external
linkage that are redeclared as
- fprintf,
-
effect of # flag character on
o
(octal) conversion
- fscanf,
-
behavior of
n
specifier for
definition of input item for
- ftell and fgetpos,
-
use of results from successful calls to
- function
-
call expression, value of
exceeding environmental limit in
call to library
parameter: see parameter
source of result may overlap the area
it is copied to
- function-like macro
-
name ending macro replacement list
names with nonstandard characters, undefined
behavior of
- header name
-
preprocessing token, recognition
in
#include
directives
- identifier,
-
declared in more than one header, an
in function parameter declaration that is either
parameter or typedef name
redeclared extern
, linkage of
redeclared extern
, type of
- #include
-
directive, header name tokens in
- incomplete
-
array type, completion by default
initialization
struct type, completion of
- index
-
entry for
static
storage-class specifier in standard
past the declared limits in array
- initialization,
-
copying of unnamed members during
ignoring unnamed structure or union
members in
of array of unspecified size
of static objects with 0
- input item,
-
definition of
fscanf
's
- integral type
-
compatible with enum type, unknown
- keyword,
-
conversion of preprocessing token to
- library functions
-
calls that exceed an environmental limit
- linkage
-
of
extern
identifiers
with visible declaration
- lvalue
-
used to access the value of an object,
legal type of
- macro
-
argument list with new-line character in
preprocessing directive
object-like require white space between
name and nonstandard characters
parentheses around replacement list of
standard object-like
replacement list ending with function-like macro
name
- main,
-
program without
- members,
-
effects of storage-class specifier on
struct or union
unnamed
recursive initialization with 0
- mktime(),
-
error result of
- n
-
conversion specifier for
fscanf
- new-line character
-
ends a preprocessing directive, even within
function-like macro invocation
- o
-
conversion specification, effect of # flag
character on.
- object,
-
access of value stored in
- parameter
-
name or typedef name in function
parameter declaration, ambiguity
type list consisting
of qualified void
with function, array, or qualified type
- parentheses
-
around standard object-like macro
replacement lists
- preprocessing
-
directive with new-line character
in macro argument list
token converted to keyword if possible
- recognition
-
of header name tokens in
#include
directives
- redeclaration
-
of identifiers with internal or external linkage, resulting
linkage
of identifiers with internal or external linkage, resulting
type
- return
-
value of function, pass by copying
- signal
-
numbers, different integral constant expressions
for
- sizeof
-
enum type in its enum constant declaration
- storage-class specifier
-
for
void
as a function
parameter type list
static
, index entry for
unions or aggregate objects declared with
- string
-
functions, value 0 for length parameter
n
in
literal recognized as header name
in #include
directive
- strtol,
-
difference between
fscanf
and
- struct,
-
hack, undefined behavior of
members: see members
or union type, point of completion of
incomplete
union and array, see aggregate
and union types
- subscript
-
exceeding declared range in array
- time_t,
-
missing cast to in
mktime()
example
- type
-
and value of function call
incomplete struct
of assignment-expression, example for
conversion to
of lvalue used to access the value of an object,
legal
of redeclared identifiers with internal
or external linkage
qualifier for void
as a
function parameter type list
qualifier of function parameters in type
compatibility and composite type
that is compatible to enum type,
integral
- typedef name
-
or parameter name in function parameter
declaration, ambiguity
- undefined behavior
-
doesn't override need to diagnose constraint
violations
for function-like macro name at the end
of an expanded replacement list
for parameter type list consisting
of qualified void
if a call to a library function exceeds an
environmental limit
of program without main()
of sizeof
when applied to an enum
in its enum constant declaration
when array subscript exceeds declared range
when n
-specifier for fscanf
isn't one of
%n %hn %ln
- union,
-
members: see members
or struct type, point of completion of
incomplete
structs, and arrays:
see aggregate and union types
- value
-
and type of function call
stored in an object, legal ways of
accessing the
- void
-
in parameter type list with type qualifier or storage-class specifier
- white space
-
between object-like macro name and special
character
Markup by Jutta Degener; introduction by Clive
Feather and Jutta Degener, 1994