Ritchie
measured in bytes, of the corresponding storage area. Therefore, indirection through a pointer
implied no runtime
overhead to scale the pointer from word to byte offset. On the other hand,
the machine code for array subscripting and pointer arithmetic now depended on the type of the
array or the pointer: to compute
the size of the object referred to.
These semantics represented an easy transition from B, and I experimented with them for
some months. Problems became evident when I tried to extend the type notation, especially to
add structured (record) types. Structures, it seemed, should map in an intuitive way onto memory
in the machine, but in a structure containing an array, there was no good place to stash the pointer
containing the base of the array, nor any convenient way to arrange that it be initialized. For
example, the directory entries of early Unix systems might be described in C as
iarray[i] or ipointer+i implied scaling the addend i bystruct {
int inumber;
char name[14];
};
I wanted the structure not merely to characterize an abstract object but also to describe a collection
of bits that might be read from a directory. Where could the compiler hide the pointer to
name
space for pointers could be hidden somehow, how could I handle the technical problem of properly
initializing these pointers when allocating a complicated object, perhaps one that specified
structures containing arrays containing structures to arbitrary depth?
The solution constituted the crucial jump in the evolutionary chain between typeless BCPL
and typed C. It eliminated the materialization of the pointer in storage, and instead caused the
creation of the pointer when the array name is mentioned in an expression. The rule, which survives
in today’s C, is that values of array type are converted, when they appear in expressions,
into pointers to the first of the objects making up the array.
This invention enabled most existing B code to continue to work, despite the underlying
shift in the language’s semantics. The few programs that assigned new values to an array name to
adjust its origin
the new language retained a coherent and workable (if unusual) explanation of the semantics
of arrays, while opening the way to a more comprehensive type structure.
The second innovation that most clearly distinguishes C from its predecessors is this fuller
type structure and especially its expression in the syntax of declarations. NB offered the basic
types
composition. Generalization was required: given an object of any type, it should be possible to
describe a new object that gathers several into an array, yields it from a function, or is a pointer to
it.
For each object of such a composed type, there was already a way to mention the underlying
object: index the array, call the function, use the indirection operator on the pointer. Analogical
reasoning led to a declaration syntax for names mirroring that of the expression syntax in which
the names typically appear. Thus,
that the semantics demanded? Even if structures were thought of more abstractly, and the possible in B and BCPL, meaningless in C were easily repaired. More important,int and char, together with arrays of them, and pointers to them, but no further ways ofint i, *pi, **ppi;
declare an integer, a pointer to an integer, a pointer to a pointer to an integer. The syntax of these
declarations reflects the observation that
an expression. Similarly,
i, *pi, and **ppi all yield an int type when used inint f(), *f(), (*f)();
declare a function returning an integer, a function returning a pointer to an integer, a pointer to a
function returning an integer;
int *api[10], (*pai)[10];
declare an array of pointers to integers, and a pointer to an array of integers. In all these cases the
No comments:
Post a Comment
THE WORLD NEW TECHNOLOGY