Appendix C - Summary of Changes (p. 259)
Since the publication of the first edition of this book, the definition of the C language has undergone changes. Almost all were extensions of the original language, and were carefully designed to remain compatible with existing practice; some repaired ambiguities in the original description; and some represent modifications that change existing practice. Many of the new facilities were announced in the documents accompanying compilers available from AT & T, and have subsequently been adopted by other suppliers of C compilers. More recently, the ANSI committee standardizing the language incorporated most of these changes, and also introduced other significant modifications. Their report was in part anticipated by some commercial compilers even before issuance of the formal C standard.
This Appendix summarizes the differences between the language defined by the first edition of this book, and that expected to be defined by the final Standard. It treats only the language itself, not its environment and library; although these are an important part of the Standard, there is little to compare with, because the first edition did not attempt to prescribe an environment or library.
- Preprocessing is more carefully defined in the Standard than in the first edition, and is extended: it is explicitly token based; there are new operators for catenation of tokens (
##
), and creation of strings (#
); there are new control lines like#elif
and#pragma
; redeclaration of macros by the same token sequence is explicitly permitted; parameters inside strings are no longer replaced. Splicing of lines by\
is permitted everywhere, not just in strings and macro definitions. See §A12. - The minimum significance of all internal identifiers is increased to 31 characters; the smallest mandated significance of identifiers with external linkage remains 6 monocase letters. (Many implementations provide more.)
- Trigraph sequences introduced by
??
allow representation of characters lacking in some character sets. Escapes for#\^[]{}|~
: are defined; see §A12.1. Observe that the introduction of trigraphs may change the meaning of strings containing the sequence??
. - New keywords (
void
,const
,volatile
,signed
,enum
) are introduced. The stillbornentry
keyword is withdrawn. - New escape sequences, for use within character constants and string literals, are defined. The effect of following
\
by a character not part of an approved escape sequence is undefined. See §A2.5.2. - Everyone's favorite trivial change:
8
and9
are not octal digits. - The Standard introduces a larger set of suffixes to make the type of constants explicit:
U
orL
for integers,F
orL
for floating. It also refines the rules for the type of unsuffixed constants (§A2.5). - Adjacent string literals are concatenated.
- There is a notation for wide-character string literals and character constants; see §A2.6.
- Characters; as well as other types, may be explicitly declared to carry, or not to carry, a sign by using the keywords
signed
orunsigned
. The locutionlong
float
as a synonym fordouble
is withdrawn, butlong double
may be used to declare an extra-precision floating quantity. - For some time, type
unsigned char
has been available. The standard introduces thesigned
keyword to make signedness explicit forchar
and other integral objects. - The
void
type has been available in most implementations for some years. The Standard introduces the use of thevoid *
type as a generic pointer type; previouslychar *
played this role. At the same time, explicit rules are enacted against mixing pointers and integers, and pointers of different type, without the use of casts. - The Standard places explicit minima on the ranges of the arithmetic types, and mandates headers (
<limits.h>
and<float.h>
) giving the characteristics of each particular implementation. - Enumerations are new since the first edition of this book.
- The Standard adopts from C++ the notion of type qualifier, for example const (§A8.2).
- Strings are no longer modifiable, and so may be placed in read-only memory.
- The "usual arithmetic conversions" are changed, essentially from "for integers,
unsigned
always wins; for floating point, always usedouble
" to "promote to the smallest capacious-enough type." See §A6.5. - The old assignment operators like = + are truly gone. Also, assignment operators are now single tokens; in the first edition, they were pairs, and could be separated by white space.
- A compiler's license to treat mathematically associative operators as computationally associative is revoked.
- A unary
+
operator is introduced for symmetry with unary-
. - A pointer to a function may be used as a function designator without an explicit
*
operator. See §A7.3.2. - Structures may be assigned, passed to functions, and returned by functions.
- Applying the address-of operator to arrays is permitted, and the result is a pointer to the array.
- The
sizeof
operator, in the first edition, yielded typeint
; subsequently, many implementations made itunsigned
. The Standard makes its type explicitly implementation-dependent, but requires the type,size_t
, to be defined in a standard header (<stddef.h>
). A similar change occurs in the type (ptrdiff_t
) of the difference between pointers. See §A7.4.8 and §A7.7. - The address-of operator
&
may not be applied to an object declaredregister
, even if the implementation chooses not to keep the object in a register. - The type of a shift expression is that of the left operand; the right operand can't promote the result. See §A7.8.
- The Standard legalizes the creation of a pointer just beyond the end of an array, and allows arithmetic and relations on it; see §A7.7.
- The Standard introduces (borrowing from C++) the notion of a function prototype declaration that incorporates the types of the parameters, and includes an explicit recognition of variadic functions together with an approved way of dealing with them. See §§A7.3.2, A8.6.3, B7. The older style is still accepted, with restrictions.
- Empty declarations, which have no declarators and don't declare at least a structure, union, or enumeration, are forbidden by the Standard. On the other hand, a declaration with just a structure or union tag redeclares that tag even if it was declared in an outer scope.
- External data declarations without any specifiers or qualifiers (just a naked declarator) are forbidden.
- Some implementations, when presented with an
extern
declaration in an inner block, would export the declaration to the rest of the file. The Standard makes it clear that the scope of such a declaration is just the block. - The scope of parameters is injected into a function's compound statement, so that variable declarations at the top level of the function cannot hide the parameters.
- The name spaces of identifiers are somewhat different. The Standard puts all tags in a single name space, and also introduces a separate name space for labels; see §A11.1. Also, member names are associated with the structure or union of which they are a part. (This has been common practice from some time.)
- Unions may be initialized; the initializer refers to the first member.
- Automatic structures, unions, and arrays may be initialized, albeit in a restricted way.
- Character arrays with an explicit size may be initialized by a string literal with exactly that many characters (the
\0
is quietly squeezed out). - The controlling expression, and the case labels, of a switch may have any integral type.