Introduction

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.


Normative Changes to ISO/IEC 9899:1990

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:
to:
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]
to:
An object shall have its stored value accessed only by an lvalue expression that has one of the following types:[36]
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:
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:
Add to subclause G.2, page 200:
Add to subclause G.2, page 201:
Add to subclause G.2, page 202:
Add to subclause G.2, page 203:
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

Permuted Index

(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