C (Programming Language)

Google+ Pinterest LinkedIn Tumblr +

Design

C is an imperative (procedural) systems implementation language. It was designed to be compiled using a relatively straightforward compiler, to provide low-level access to memory, to provide language constructs that map efficiently to machine instructions, and to require minimal run-time support. C was therefore useful for many applications that had formerly been coded in assembly language.

Despite its low-level capabilities, the language was designed to encourage cross-platform programming. A standards-compliant and portably written C program can be compiled for a very wide variety of computer platforms and operating systems with few changes to its source code. The language has become available on a very wide range of platforms, from embedded microcontrollers to supercomputers.

Characteristics

Like most imperative languages in the ALGOL tradition, C has facilities for structured programming and allows lexical variable scope and recursion, while a static type system prevents many unintended operations. In C, all executable code is contained within functions. Function parameters are always passed by value. Pass-by-reference is simulated in C by explicitly passing pointer values. Heterogeneous aggregate data types (struct) allow related data elements to be combined and manipulated as a unit. C program source text is free-format, using the semicolon as a statement terminator.

C also exhibits the following more specific characteristics:

  • Partially weak typing; for instance, characters can be used as integers

  • Low-level access to computer memory by converting machine addresses to typed pointers

  • Function and data pointers supporting ad hoc run-time polymorphism

  • array indexing as a secondary notion, defined in terms of pointer arithmetic

  • A preprocessor for macro definition, source code file inclusion, and conditional compilation

  • Complex functionality such as I/O, string manipulation, and mathematical functions consistently delegated to library routines

  • A large number of compound operators, such as +=, -=, *=, ++, etc.

History

Early developments

The initial development of C occurred at AT&T Bell Labs between 1969 and 1973;[3] according to Ritchie, the most creative period occurred in 1972. It was named “C” because its features were derived from an earlier language called “B”, which according to Ken Thompson was a stripped-down version of the BCPL programming language.

The origin of C is closely tied to the development of the Unix operating system, originally implemented in assembly language on a PDP-7 by Ritchie and Thompson, incorporating several ideas from colleagues. Eventually they decided to port the operating system to a PDP-11. B’s inability to take advantage of some of the PDP-11’s features, notably byte addressability, led to the development of an early version of C.

The original PDP-11 version of the Unix system was developed in assembly language. By 1973, with the addition of struct types, the C language had become powerful enough that most of the Unix kernel was rewritten in C. This was one of the first operating system kernels implemented in a language other than assembly. (Earlier instances include the Multics system (written in PL/I), and MCP (Master Control Program) for the Burroughs B5000 written in ALGOL in 1961.)

K&R C

In 1978, Brian Kernighan and Dennis Ritchie published the first edition of The C Programming Language.[7] This book, known to C programmers as “K&R”, served for many years as an informal specification of the language. The version of C that it describes is commonly referred to as K&R C. The second edition of the book[1] covers the later ANSI C standard.

K&R introduced several language features:

  • standard I/O library

  • long int data type

  • unsigned int data type

  • compound assignment operators of the form =op (such as =-) were changed to the form op= to remove the semantic ambiguity created by such constructs as i=-10, which had been interpreted as i =- 10 instead of the possibly intended i = -10

Even after the publication of the 1989 C standard, for many years K&R C was still considered the “lowest common denominator” to which C programmers restricted themselves when maximum portability was desired, since many older compilers were still in use, and because carefully written K&R C code can be legal Standard C as well.

In early versions of C, only functions that returned a non-int value needed to be declared if used before the function definition; a function used without any previous declaration was assumed to return type int, if its value was used.

For example:

long some_function();/* int */ other_function();/* int */ calling_function(){long test1;register/* int */ test2;
 
    test1 = some_function();if(test1 >0)
          test2 =0;else
          test2 = other_function();return test2;}

All the above commented-out int declarations could be omitted in K&R C.

Since K&R function declarations did not include any information about function arguments, function parameter type checks were not performed, although some compilers would issue a warning message if a local function was called with the wrong number of arguments, or if multiple calls to an external function used different numbers or types of arguments. Separate tools such as Unix’s lint utility were developed that (among other things) could check for consistency of function use across multiple source files.

In the years following the publication of K&R C, several unofficial features were added to the language, supported by compilers from AT&T and some other vendors. These included:

  • void functions (i.e. functions with no return value)

  • functions returning struct or union types (rather than pointers)

  • assignment for struct data types

  • enumerated types

The large number of extensions and lack of agreement on a standard library, together with the language popularity and the fact that not even the Unix compilers precisely implemented the K&R specification, led to the necessity of standardization

Language tools

Tools have been created to help C programmers avoid some of the problems inherent in the language, such as statements with undefined behavior or statements that are not a good practice because they are more likely to result in unintended behavior or run-time errors.

Automated source code checking and auditing are beneficial in any language, and for C many such tools exist, such as Lint. A common practice is to use Lint to detect questionable code when a program is first written. Once a program passes Lint, it is then compiled using the C compiler. Also, many compilers can optionally warn about syntactically valid constructs that are likely to actually be errors. MISRA C is a proprietary set of guidelines to avoid such questionable code, developed for embedded systems.

There are also compilers, libraries and operating system level mechanisms for performing array bounds checking, buffer overflow detection, serialization and automatic garbage collection, that are not a standard part of C.

Tools such as Purify, Valgrind, and linking with libraries containing special versions of the memory allocation functions can help uncover runtime memory errors.

Share.

About Author

Leave A Reply