Comparison of Pascal and C
Encyclopedia
The computer programming language
s C
and Pascal
have similar times of origin, influences, and purposes. Both were used to design (and compile) their own compilers early in their lifetimes.
Both C and Pascal are old programming languages: The original Pascal definition appeared in 1969 and a first compiler in 1970. The first version of C appeared in 1972.
Both are descendants of the ALGOL
language series. Algol introduced structured programming
, where programs are constructed of single entry and single exit constructs such as if, while, for and case. Pascal stems directly from Algol-W, while it shared some new ideas with Algol 68
. The C language is more indirectly related to Algol, originally through B, BCPL
, and CPL, and later through Algol 68 (for example in case of struct and union) and also Pascal (for example in case of enumerations, const, typedef and booleans). Some Pascal dialects also incorporated characteristics from C.
What is documented here is the Pascal of Niklaus Wirth, as standardized as ISO 7185 in 1982. The C documented is the language of Brian W. Kernighan and Dennis M. Ritchie, as standardized in 1989. The reason is that these versions both represent the mature versions of the language, and also because they are the closest in time. C99 (the later C standard) features and features of new dialects of Pascal are not included in the comparison.
. In Pascal semicolons separate individual statements within a compound statement whereas they terminate the statement in C. They are also syntactically part of the statement itself in C (transforming an expression into a statement). This difference manifests itself primarily in two situations:
A superfluous semicolon can be put on the last line before end, thereby formally inserting an empty statement.
In traditional Pascal, there are
Modern Pascal, like Object Pascal (Delphi, FPC), as well as modern C implementations allow C++ style comments
Both C and Pascal use keyword
s (words reserved for use by the language itself). Examples are if, while, const, for and goto, which are keywords that happen to be common to both languages. In C, the basic built-in type names are also keywords (e.g. int, char) or combinations of keywords (e.g. unsigned char), while in Pascal the built-in type names are predefined normal identifiers.
s are defined by the keyword
In Pascal functions, begin and end delimit a block of statements (proper), while C functions use "{" and "}" to delimit a block of statements optionally preceded by declarations. C (prior to C99) strictly defines that any declarations must occur before the statements within a particular block but allows blocks to appear within blocks, which is a way to go around this. Pascal is strict that declarations must occur before statements, but allows definitions of types and functions - not only variable declarations - to be encapsulated by function definitions to any level of depth.
C it is necessary to have access to a symbol table for types, while in Pascal there is only one such construct, assignment. For instance, the C fragment
C accommodates different sizes and signed and unsigned
modes for integers by using modifiers such as
type a = 1..100;
b = -20..20;
c = 0..100000;
This subrange feature is not supported by C.
A major, if subtle, difference between C and Pascal is how they promote integer operations. In Pascal, the result of an operation is defined for all integer/subrange types, even if intermediate results do not fit into an integer. The result is undefined only if it does not fit into the interger/subrange on the left hand side of the assigment. This may imply an artificial restriction on the range of integer types, or may require slow execution to handle the intermediate results: However, the compiler may take advantage of restricted subranges to produce more efficient code.
In C, operands must first be promoted to the size of the required result: intermediate results are undefined if they do not fit into the range of the promoted operands. If range of the required result is greater than the range of operands, this normally produces slow inefficient code, even from a good optimising compiler. However, a C compiler is never required or expected to handle out of range intermediate results: it is the programmers responsibility to ensure that all intermediate results fit into the operand range.
The (only) pre-Standard implementation of C as well as Small-C et al. allowed integer and pointer types to be relatively freely intermixed.
This integer nature of
unsigned char uc = 255; /* common limit */
signed char sc = -128; /* common negative limit */
Whether the
In Pascal, characters and integers are distinct types. The inbuilt compiler functions
is an enumerated type. The possible values of boolean are false and true. For conversion to integer, ord is used:
i := ord(b);
There is no standard function for integer to boolean, however, the conversion is simple in practice:
b := i <> 0;
C has binary valued relational operators (<, >, , !=, <=, >=) which may be regarded as boolean in the sense that they always give results which are either zero or one. As all tests (&&, ||, ?:, if, while, etc.) are performed by zero-checks, false is represented by zero, while true is represented by any other value.
operators
to perform boolean operations. Care needs to be taken because the semantics are different when operands make use of more than one bit to represent a value.
Pascal has another more abstract, high level method of dealing with bitwise data, sets. Sets allow the programmer to set, clear, intersect, and unite bitwise data values, rather than using direct bitwise operators (which are available in modern Pascal as well). Example;
Pascal:
Status := Status + [StickyFlag];
Status := Status - [StickyFlag];
if (StickyFlag in Status) then ...
or
Pascal:
Status := Status or StickyFlag;
Status := Status and not StickyFlag;
if StickyFlag and Status = StickyFlag then ...
C:
Status |= StickyFlag;
Status &= ~StickyFlag;
if (Status & StickyFlag) { ...
Although bit operations on integers and operations on sets can be considered similar if the sets are implemented using bits, there is no direct parallel between their uses unless a non-standard conversion between integers and sets is possible.
types than Pascal. In C, integers may be implicitly converted to floating point numbers, and vice versa (though possible precision loss may be flagged by warnings). In Pascal, integers may be implicitly converted to
or round
off the fraction, respectively.
type
color = (red, green, blue);
var
a: color;
A C example:
enum color {red, green, blue};
enum color a;
The behavior of the types in the two languages however is very different. In C,
s of other complex types, including other arrays. However, there the similarity between the languages ends. C arrays are simply defined by a base type and the number of elements:
int a[SIZE];
and are always indexed from 0 up to SIZE-1 (i.e. modulo SIZE).
In Pascal, the range of indices is often specified by a subrange (as introduced under simple types above). The ten elements of
var a : array[0..9] of integer;
would be indexed by 0..9 (just as in C in this case). Array indices can be any ordinal type, however, not just ranges:
type
TColor = (red, green, blue); (* enumeration *)
RGB = array[TColor] of 0..255;
var picture : array[1..640, 1..480] of RGB
var palette : array[byte, 0..2] of byte
Strings consisting of n (>1) characters are defined as packed arrays with range 1..n.
While arrays in C are fixed, pointers to them are interchangeable. This flexibility allows C to manipulate any length array using the same code. It also leaves the programmer with the responsibility not to write outside the allocated array, as no checks are built in into the language itself.
In Pascal, arrays are a distinct type from pointers. This makes bounds checking
for arrays possible from a compiler perspective. Practically all Pascal compilers support range checking as a compile option.
The ability to both have arrays that change length at runtime, and be able to check them under language control, is often termed "dynamic arrays". In Pascal the number of elements in each array type is determined at compile-time and cannot be changed during the execution of the program. Hence, it is not possible to define an array whose length depends in any way on program data.
C has the ability to initialize arrays of arbitrary length. The
static char *wordlist[] = {
"print", "out", "the", "text", "message" };
static int listSize = (sizeof(wordlist)/sizeof(wordlist[0]));
int i;
for (i=0; i
puts(wordlist[i]);
for (i=listSize-1; i>=0; i--)
puts(wordlist[i]);
Pascal has neither array initialization (outside of the case of strings) nor a means of determining arbitrary array sizes at compile time.
One way of implementing the above example in Pascal, but without the automatic size adjustment, is:
const
minlist = 1;
maxlist = 5;
maxword = 7;
type
listrange = minlist .. maxlist;
wordrange = 1..maxword;
word = record
contents: packed array [wordrange] of char;
length: wordrange
end;
wordlist = array[listrange] of word;
var
i: integer;
words: wordlist;
procedure CreateList(var w: wordlist);
begin
w[1].contents := 'print ';
w[1].length := 5;
w[2].contents := 'out ';
w[2].length := 3;
w[3].contents := 'the ';
w[3].length := 3;
w[4].contents := 'text ';
w[4].length := 4;
w[5].contents := 'message';
w[5].length := 7;
end;
begin
CreateList(words);
for i := minlist to maxlist do
with words[i] do
WriteLn(contents: length);
for i := maxlist downto minlist do
with words[i] do
WriteLn(contents: length)
end.
In Pascal a string literal of length n is compatible with the type
Pascal suffers from a problem in that it has no support for variable-length arrays, and so any set of routines to perform string operations is dependent on a particular string size. However, the now standardized Pascal "conformant array parameter" extension solves this to a great extent, and many or even most implementations of Pascal have support for strings native to the language.
C automatically terminates string literals with a trailing null character as an end-of-string "sentinel":
const char *p;
p = "the rain in Spain"; /* null-terminated */
Null-termination must be manually maintained for string variables stored in arrays (this is often partly handled by library routines).
C does not have built-in string or array assignment, so the string is not actually being transferred to p, but rather p is being made to point to the constant string in memory.
" types. In C, they are termed "structures".
struct a {
int b;
char c;
};
type a = record
b: integer;
c: char;
end;
In C, the exact bit length of a field can be specified:
struct a {
unsigned int b:3;
unsigned int c:1;
};
How much storage is actually used depends on characteristics (e.g. word-alignment) of the target system.
This feature is available in Pascal by using the subrange construct (3 bits gives a range from 0 to 7) in association with the keyword packed:
type a = packed record
b: 0..7;
c: 0..1;
end;
Both C and Pascal support records which can include different fields overlapping each other:
union a {
int a;
float b;
};
type a = record
case boolean of
false: (a: integer);
true: (b: real)
end;
Both language processors are free to allocate only as much space for these records as needed to contain the largest type in the union/record.
The biggest difference between C and Pascal is that Pascal supports the explicit use of a "tagfield"
for the language processor to determine if the valid component of the variant record is being accessed:
type a = record
case q: boolean of
false: (a: integer);
true: (b: real)
end;
In this case, the tagfield q must be set to the right state to access the proper parts of the record.
Pointers
In C, pointers can be made to point at most program entities, including objects or functions:
int a;
int *b;
int (*compare)(int c, int d);
int MyCompare(int c, int d);
b = &a;
compare = &MyCompare;
In C, since arrays and pointers have a close equivalence, the following are the same:
a = b[5];
a = *(b+5);
a = *(5+b);
a = 5[b];
Thus, pointers are often used in C as just another method to access arrays.
To create dynamic data, the library functions
Pascal doesn't have the same kind of pointers as C, but it does have an indirection operator that covers the most common use of C pointers. Each pointer is bound to a single dynamic data item, and can only be moved by assignment:
type a = ^integer;
var b, c: a;
new(b);
c := b;
Pointers in Pascal are type safe; i.e. a pointer to one data type can only be assigned to a pointer of the same data type. Also pointers can never be assigned to non-pointer variables. Pointer arithmetic (a common source of programming errors in C, especially when combined with endianness
issues and platform-independent type sizes) is not permitted in Pascal.
All of these restrictions reduce the possibility of pointer-related errors in Pascal compared to C, but do not prevent invalid pointer references in Pascal altogether. For example, a runtime error will occur if a pointer is referenced before it has been initialized or after it has been disposed.
Pascal has four levels:
while C has 15 levels:
, uses the mathematical equality operator for equality test and the symbol
It is a common mistake, either due to inexperience or a simple typing error, to accidentally put assignment expressions in conditional statements such as
designed Pascal, the desire was to limit the number of levels of precedence (fewer parse routines, after all). So the OR and exclusive OR operators are treated just like an Addop and processed at the level of a math expression. Similarly, the AND is treated like a Mulop and processed with Term. The precedence levels are
Notice that there is only ONE set of syntax rules, applying to both kinds of operators. According to this grammar, then, expressions like
are perfectly legal. And, in fact, they are, as far as the parser is concerned. Pascal doesn't allow the mixing of arithmetic and Boolean variables, and things like this are caught at the semantic level, when it comes time to generate code for them, rather than at the syntax level.
The authors of C took a diametrically opposite approach: they treat the operators as different, and have something much more akin to our seven levels of precedence. In fact, in C there are no fewer than 15 levels. That's because C also has the operators '=', '+=' and its kin, '<<', '>>', '++', '--', etc. Although in C the arithmetic and Boolean operators are treated separately, the variables are not: a Boolean test can be made on any integer value. A strange consequence of this grammar is that every expression is potentially a Boolean expression.
In C, dependence on boolean evaluation order is perfectly legal, and often systematically employed using the
Programming language
A programming language is an artificial language designed to communicate instructions to a machine, particularly a computer. Programming languages can be used to create programs that control the behavior of a machine and/or to express algorithms precisely....
s C
C (programming language)
C is a general-purpose computer programming language developed between 1969 and 1973 by Dennis Ritchie at the Bell Telephone Laboratories for use with the Unix operating system....
and Pascal
Pascal (programming language)
Pascal is an influential imperative and procedural programming language, designed in 1968/9 and published in 1970 by Niklaus Wirth as a small and efficient language intended to encourage good programming practices using structured programming and data structuring.A derivative known as Object Pascal...
have similar times of origin, influences, and purposes. Both were used to design (and compile) their own compilers early in their lifetimes.
Both C and Pascal are old programming languages: The original Pascal definition appeared in 1969 and a first compiler in 1970. The first version of C appeared in 1972.
Both are descendants of the ALGOL
ALGOL
ALGOL is a family of imperative computer programming languages originally developed in the mid 1950s which greatly influenced many other languages and became the de facto way algorithms were described in textbooks and academic works for almost the next 30 years...
language series. Algol introduced structured programming
Structured programming
Structured programming is a programming paradigm aimed on improving the clarity, quality, and development time of a computer program by making extensive use of subroutines, block structures and for and while loops - in contrast to using simple tests and jumps such as the goto statement which could...
, where programs are constructed of single entry and single exit constructs such as if, while, for and case. Pascal stems directly from Algol-W, while it shared some new ideas with Algol 68
ALGOL 68
ALGOL 68 isan imperative computerprogramming language that was conceived as a successor to theALGOL 60 programming language, designed with the goal of a...
. The C language is more indirectly related to Algol, originally through B, BCPL
BCPL
BCPL is a procedural, imperative, and structured computer programming language designed by Martin Richards of the University of Cambridge in 1966.- Design :...
, and CPL, and later through Algol 68 (for example in case of struct and union) and also Pascal (for example in case of enumerations, const, typedef and booleans). Some Pascal dialects also incorporated characteristics from C.
What is documented here is the Pascal of Niklaus Wirth, as standardized as ISO 7185 in 1982. The C documented is the language of Brian W. Kernighan and Dennis M. Ritchie, as standardized in 1989. The reason is that these versions both represent the mature versions of the language, and also because they are the closest in time. C99 (the later C standard) features and features of new dialects of Pascal are not included in the comparison.
Syntax
Syntactically, Pascal is much more Algol-like than C. English keywords are retained where C uses punctuation symbols — Pascal hasand
, or
, and mod
where C uses &&
, ||
, and %
for example. However, C is actually more Algol-like than Pascal regarding (simple) declarations, retaining the type-name variable-name syntax. For example, C can accept declarations at the start of any block, not just the outer block of a function.Semicolon use
Another, more subtle, difference is the role of the semicolonSemicolon
The semicolon is a punctuation mark with several uses. The Italian printer Aldus Manutius the Elder established the practice of using the semicolon to separate words of opposed meaning and to indicate interdependent statements. "The first printed semicolon was the work of ... Aldus Manutius"...
. In Pascal semicolons separate individual statements within a compound statement whereas they terminate the statement in C. They are also syntactically part of the statement itself in C (transforming an expression into a statement). This difference manifests itself primarily in two situations:
- there can never be a semicolon directly before
else
in Pascal whereas it is mandatory in C (unless a block statement is used) - the last statement before an
end
is not required to be followed by a semicolon
A superfluous semicolon can be put on the last line before end, thereby formally inserting an empty statement.
Comments
In traditional C, there are only/* block comments */
. This is only supported by certain Pascal dialects like MIDletPascal.In traditional Pascal, there are
{ block comments }
and (* block comments *)
.Modern Pascal, like Object Pascal (Delphi, FPC), as well as modern C implementations allow C++ style comments
// comments
Identifiers and keywords
C and Pascal differ in their interpretation of upper and lower case. C is case sensitive while Pascal is not, thusMyLabel
and mylabel
are distinct names in C but identical in Pascal. In both languages, identifiers consist of letters and digits, with the rule that the first character may not be a digit. In C, the underscore counts as a letter, so even _abc is a valid name. Names with a leading underscore are often used to differentiate special system identifiers in C.Both C and Pascal use keyword
Keyword (computer programming)
In computer programming, a keyword is a word or identifier that has a particular meaning to the programming language. The meaning of keywords — and, indeed, the meaning of the notion of keyword — differs widely from language to language....
s (words reserved for use by the language itself). Examples are if, while, const, for and goto, which are keywords that happen to be common to both languages. In C, the basic built-in type names are also keywords (e.g. int, char) or combinations of keywords (e.g. unsigned char), while in Pascal the built-in type names are predefined normal identifiers.
Definitions, declarations, and blocks
In Pascal, procedure definitions start with keywords procedure or function and type definitions with type. In C, function definitions are determined by syntactical context while type definitions use the keywordtypedef
. Both languages use a mix of keywords and punctuation for definitions of complex types; for instance, arrays are defined by the keyword array in Pascal and by punctuation in C, while enumerationEnumeration
In mathematics and theoretical computer science, the broadest and most abstract definition of an enumeration of a set is an exact listing of all of its elements . The restrictions imposed on the type of list used depend on the branch of mathematics and the context in which one is working...
s are defined by the keyword
enum
in C but by punctuation in Pascal.In Pascal functions, begin and end delimit a block of statements (proper), while C functions use "{" and "}" to delimit a block of statements optionally preceded by declarations. C (prior to C99) strictly defines that any declarations must occur before the statements within a particular block but allows blocks to appear within blocks, which is a way to go around this. Pascal is strict that declarations must occur before statements, but allows definitions of types and functions - not only variable declarations - to be encapsulated by function definitions to any level of depth.
Implementation
The grammars of both languages are of a similar size. From an implementation perspective the main difference between the two languages is that to parseParsing
In computer science and linguistics, parsing, or, more formally, syntactic analysis, is the process of analyzing a text, made of a sequence of tokens , to determine its grammatical structure with respect to a given formal grammar...
C it is necessary to have access to a symbol table for types, while in Pascal there is only one such construct, assignment. For instance, the C fragment
X * Y;
could be a declaration of Y
to be an object whose type is pointer to X
, or a statement-expression that multiplies X
and Y
. The corresponding Pascal fragment var Y:^X;
is unambiguous without a symbol table.Integers
Pascal requires all variable and function declarations to specify their type explicitly. In traditional C, a type name may be omitted in most contexts and the default typeint
(which corresponds to integerIntegerThe integers are formed by the natural numbers together with the negatives of the non-zero natural numbers .They are known as Positive and Negative Integers respectively...
in Pascal) is then implicitly assumed (however, such defaults are considered bad practice in C and are often flagged by warnings).C accommodates different sizes and signed and unsigned
Signedness
In computing, signedness is a property of data types representing numbers in computer programs. A numeric variable is signed if it can represent both positive and negative numbers, and unsigned if it can only represent non-negative numbers .As signed numbers can represent negative numbers, they...
modes for integers by using modifiers such as
long
, short
, signed
, unsigned
, etc. The exact meaning of the resulting integer type is machine-dependent, however, what can be guaranteed is that int
is at least 16 bits, long int
is no shorter than int
and short int
is no longer than int
.Subranges
In Pascal, a similar end is performed by declaring a subrange of integer (a compiler may then choose to allocate a smaller amount of storage for the declared variable):type a = 1..100;
b = -20..20;
c = 0..100000;
This subrange feature is not supported by C.
A major, if subtle, difference between C and Pascal is how they promote integer operations. In Pascal, the result of an operation is defined for all integer/subrange types, even if intermediate results do not fit into an integer. The result is undefined only if it does not fit into the interger/subrange on the left hand side of the assigment. This may imply an artificial restriction on the range of integer types, or may require slow execution to handle the intermediate results: However, the compiler may take advantage of restricted subranges to produce more efficient code.
In C, operands must first be promoted to the size of the required result: intermediate results are undefined if they do not fit into the range of the promoted operands. If range of the required result is greater than the range of operands, this normally produces slow inefficient code, even from a good optimising compiler. However, a C compiler is never required or expected to handle out of range intermediate results: it is the programmers responsibility to ensure that all intermediate results fit into the operand range.
The (only) pre-Standard implementation of C as well as Small-C et al. allowed integer and pointer types to be relatively freely intermixed.
Character types
In C the character type ischar
which is a kind of integer that is no longer than short int
, . Expressions such as 'x'+1
are therefore perfectly legal, as are declarations such as int i='i';
and char c=74;
.This integer nature of
char
(an eight-bit byte on most machines) is clearly illustrated by declarations such asunsigned char uc = 255; /* common limit */
signed char sc = -128; /* common negative limit */
Whether the
char
type should be regarded as signed
or unsigned
by default is up to the implementation.In Pascal, characters and integers are distinct types. The inbuilt compiler functions
ord
and chr
can be used to typecast single characters to the corresponding integer value of the character set in use, and vice versa. e.g. on systems using the ASCII character set ord('1') = 49
and chr(9)
is a TAB character.Boolean types
In Pascal, booleanBoolean datatype
In computer science, the Boolean or logical data type is a data type, having two values , intended to represent the truth values of logic and Boolean algebra...
is an enumerated type. The possible values of boolean are false and true. For conversion to integer, ord is used:
i := ord(b);
There is no standard function for integer to boolean, however, the conversion is simple in practice:
b := i <> 0;
C has binary valued relational operators (<, >, , !=, <=, >=) which may be regarded as boolean in the sense that they always give results which are either zero or one. As all tests (&&, ||, ?:, if, while, etc.) are performed by zero-checks, false is represented by zero, while true is represented by any other value.
Bitwise operations
The C programmer may sometimes use bitwiseBitwise operation
A bitwise operation operates on one or more bit patterns or binary numerals at the level of their individual bits. This is used directly at the digital hardware level as well as in microcode, machine code and certain kinds of high level languages...
operators
Operator (programming)
Programming languages typically support a set of operators: operations which differ from the language's functions in calling syntax and/or argument passing mode. Common examples that differ by syntax are mathematical arithmetic operations, e.g...
to perform boolean operations. Care needs to be taken because the semantics are different when operands make use of more than one bit to represent a value.
Pascal has another more abstract, high level method of dealing with bitwise data, sets. Sets allow the programmer to set, clear, intersect, and unite bitwise data values, rather than using direct bitwise operators (which are available in modern Pascal as well). Example;
Pascal:
Status := Status + [StickyFlag];
Status := Status - [StickyFlag];
if (StickyFlag in Status) then ...
or
Pascal:
Status := Status or StickyFlag;
Status := Status and not StickyFlag;
if StickyFlag and Status = StickyFlag then ...
C:
Status |= StickyFlag;
Status &= ~StickyFlag;
if (Status & StickyFlag) { ...
Although bit operations on integers and operations on sets can be considered similar if the sets are implemented using bits, there is no direct parallel between their uses unless a non-standard conversion between integers and sets is possible.
A note on implementation
During expression evaluation, and in both languages, a boolean value may be internally stored as a single bit, a single byte, a full machine word, a position in the generated code, or as a condition code in a status register, depending on machine, compiler, and situation; these factors are usually more important than the language compiled.Floating point types
C has a less strict model of floating pointFloating point
In computing, floating point describes a method of representing real numbers in a way that can support a wide range of values. Numbers are, in general, represented approximately to a fixed number of significant digits and scaled using an exponent. The base for the scaling is normally 2, 10 or 16...
types than Pascal. In C, integers may be implicitly converted to floating point numbers, and vice versa (though possible precision loss may be flagged by warnings). In Pascal, integers may be implicitly converted to
real
, but conversion of real
to integer
(where information may be lost) must be done explicitly via the functions trunc
and round
, which truncateTruncation
In mathematics and computer science, truncation is the term for limiting the number of digits right of the decimal point, by discarding the least significant ones.For example, consider the real numbersThe result would be:- Truncation and floor function :...
or round
Rounding
Rounding a numerical value means replacing it by another value that is approximately equal but has a shorter, simpler, or more explicit representation; for example, replacing $23.4476 with $23.45, or the fraction 312/937 with 1/3, or the expression √2 with 1.414.Rounding is often done on purpose to...
off the fraction, respectively.
Enumeration types
Both C and Pascal include enumeration types. A Pascal example:type
color = (red, green, blue);
var
a: color;
A C example:
enum color {red, green, blue};
enum color a;
The behavior of the types in the two languages however is very different. In C,
red
becomes just a synonym for 0, green
for 1, blue
for 2, and nothing prevents a value outside this range to be assigned to the variable a
. Furthermore, operations like a = a + 1;
are strictly forbidden in Pascal; instead you would use a := succ(a);
. In C, enums can be freely converted to and from ints, but in Pascal, the function ord must be used to convert from enumerated types to integers, and there is no function to convert from integer to enumerated types.Array types
Both C and Pascal allow arrayArray data type
In computer science, an array type is a data type that is meant to describe a collection of elements , each selected by one or more indices that can be computed at run time by the program. Such a collection is usually called an array variable, array value, or simply array...
s of other complex types, including other arrays. However, there the similarity between the languages ends. C arrays are simply defined by a base type and the number of elements:
int a[SIZE];
and are always indexed from 0 up to SIZE-1 (i.e. modulo SIZE).
In Pascal, the range of indices is often specified by a subrange (as introduced under simple types above). The ten elements of
would be indexed by 0..9 (just as in C in this case). Array indices can be any ordinal type, however, not just ranges:
type
TColor = (red, green, blue); (* enumeration *)
RGB = array[TColor] of 0..255;
var picture : array[1..640, 1..480] of RGB
var palette : array[byte, 0..2] of byte
Strings consisting of n (>1) characters are defined as packed arrays with range 1..n.
Arrays and pointers
In C expressions, an identifier representing an array is treated as a constant pointer to the first element of the array, thus, given the declarationsint a[10]
and int *p;
the assignment p = a
is valid and causes p and a to point to the same array. As the identifier a
represents a constant address, a = p
is not valid however.While arrays in C are fixed, pointers to them are interchangeable. This flexibility allows C to manipulate any length array using the same code. It also leaves the programmer with the responsibility not to write outside the allocated array, as no checks are built in into the language itself.
In Pascal, arrays are a distinct type from pointers. This makes bounds checking
Bounds checking
In computer programming, bounds checking is any method of detecting whether a variable is within some bounds before its use. It is particularly relevant to a variable used as an index into an array to ensure its value lies within the bounds of the array...
for arrays possible from a compiler perspective. Practically all Pascal compilers support range checking as a compile option.
The ability to both have arrays that change length at runtime, and be able to check them under language control, is often termed "dynamic arrays". In Pascal the number of elements in each array type is determined at compile-time and cannot be changed during the execution of the program. Hence, it is not possible to define an array whose length depends in any way on program data.
C has the ability to initialize arrays of arbitrary length. The
sizeofSizeofIn the programming languages C and C++, the unary operator sizeof is used to calculate the sizes of datatypes, in number of bytes. A byte in this context is the same as an unsigned char, and may be larger than the standard 8 bits, although that is uncommon in modern implementations...
operator can be used to obtain the size of a statically initialized array in C code. For instance in the following code, the terminating index for the loop automatically adjusts should the list of strings be changed.static char *wordlist[] = {
"print", "out", "the", "text", "message" };
static int listSize = (sizeof(wordlist)/sizeof(wordlist[0]));
int i;
for (i=0; i
for (i=listSize-1; i>=0; i--)
puts(wordlist[i]);
Pascal has neither array initialization (outside of the case of strings) nor a means of determining arbitrary array sizes at compile time.
One way of implementing the above example in Pascal, but without the automatic size adjustment, is:
const
minlist = 1;
maxlist = 5;
maxword = 7;
type
listrange = minlist .. maxlist;
wordrange = 1..maxword;
word = record
contents: packed array [wordrange] of char;
length: wordrange
end;
wordlist = array[listrange] of word;
var
i: integer;
words: wordlist;
procedure CreateList(var w: wordlist);
begin
w[1].contents := 'print ';
w[1].length := 5;
w[2].contents := 'out ';
w[2].length := 3;
w[3].contents := 'the ';
w[3].length := 3;
w[4].contents := 'text ';
w[4].length := 4;
w[5].contents := 'message';
w[5].length := 7;
end;
begin
CreateList(words);
for i := minlist to maxlist do
with words[i] do
WriteLn(contents: length);
for i := maxlist downto minlist do
with words[i] do
WriteLn(contents: length)
end.
Strings
String are in both languages are primitive arrays of characters.In Pascal a string literal of length n is compatible with the type
packed array [1..n] of char
. In C a string generally has the type char[n]
.Pascal suffers from a problem in that it has no support for variable-length arrays, and so any set of routines to perform string operations is dependent on a particular string size. However, the now standardized Pascal "conformant array parameter" extension solves this to a great extent, and many or even most implementations of Pascal have support for strings native to the language.
C automatically terminates string literals with a trailing null character as an end-of-string "sentinel":
const char *p;
p = "the rain in Spain"; /* null-terminated */
Null-termination must be manually maintained for string variables stored in arrays (this is often partly handled by library routines).
C does not have built-in string or array assignment, so the string is not actually being transferred to p, but rather p is being made to point to the constant string in memory.
Record types
Both C and Pascal can declare "recordObject composition
In computer science, object composition is a way to combine simple objects or data types into more complex ones...
" types. In C, they are termed "structures".
struct a {
int b;
char c;
};
type a = record
b: integer;
c: char;
end;
In C, the exact bit length of a field can be specified:
struct a {
unsigned int b:3;
unsigned int c:1;
};
How much storage is actually used depends on characteristics (e.g. word-alignment) of the target system.
This feature is available in Pascal by using the subrange construct (3 bits gives a range from 0 to 7) in association with the keyword packed:
type a = packed record
b: 0..7;
c: 0..1;
end;
Both C and Pascal support records which can include different fields overlapping each other:
union a {
int a;
float b;
};
type a = record
case boolean of
false: (a: integer);
true: (b: real)
end;
Both language processors are free to allocate only as much space for these records as needed to contain the largest type in the union/record.
The biggest difference between C and Pascal is that Pascal supports the explicit use of a "tagfield"
Tagged union
In computer science, a tagged union, also called a variant, variant record, discriminated union, or disjoint union, is a data structure used to hold a value that could take on several different, but fixed types. Only one of the types can be in use at any one time, and a tag field explicitly...
for the language processor to determine if the valid component of the variant record is being accessed:
type a = record
case q: boolean of
false: (a: integer);
true: (b: real)
end;
In this case, the tagfield q must be set to the right state to access the proper parts of the record.
Pointers
In C, pointers can be made to point at most program entities, including objects or functions:
int a;
int *b;
int (*compare)(int c, int d);
int MyCompare(int c, int d);
b = &a;
compare = &MyCompare;
In C, since arrays and pointers have a close equivalence, the following are the same:
a = b[5];
a = *(b+5);
a = *(5+b);
a = 5[b];
Thus, pointers are often used in C as just another method to access arrays.
To create dynamic data, the library functions
malloc
and free
are used to obtain and release dynamic blocks of data. Thus, dynamic memory allocation is not built into the language processor. This is especially valuable when C is being used in operating system kernels or embedded targets as these things are very platform (not just architecture) specific and would require changing the C compiler for each platform (or operating system) that it would be used on.Pascal doesn't have the same kind of pointers as C, but it does have an indirection operator that covers the most common use of C pointers. Each pointer is bound to a single dynamic data item, and can only be moved by assignment:
type a = ^integer;
var b, c: a;
new(b);
c := b;
Pointers in Pascal are type safe; i.e. a pointer to one data type can only be assigned to a pointer of the same data type. Also pointers can never be assigned to non-pointer variables. Pointer arithmetic (a common source of programming errors in C, especially when combined with endianness
Endianness
In computing, the term endian or endianness refers to the ordering of individually addressable sub-components within the representation of a larger data item as stored in external memory . Each sub-component in the representation has a unique degree of significance, like the place value of digits...
issues and platform-independent type sizes) is not permitted in Pascal.
All of these restrictions reduce the possibility of pointer-related errors in Pascal compared to C, but do not prevent invalid pointer references in Pascal altogether. For example, a runtime error will occur if a pointer is referenced before it has been initialized or after it has been disposed.
Precedence levels
The languages differ significantly when it comes to expression evaluation, C (although not fully comparable) has almost four times as many precedence levels as Pascal.Pascal has four levels:
- Logical negation:
not
- Multiplicative:
* / div mod and
- Additive:
+ - or
- Relational:
= <> < > <= >= in
while C has 15 levels:
- Unary postfix:
[] . -> ++ --
- Unary prefix:
& * + - ! ~ ++ -- (type) sizeof
- Multiplicative:
* / %
- Additive:
+ -
- Shift:
<< >>
- Relational:
< > <= >=
- Equality:
!=
- Bitwise and:
&
- Bitwise xor:
^
- Bitwise or:
|
- Logical and:
&&
- Logical or:
||
- Conditional:
? :
- Assignment:
= += -= *= /= %= <<= >>= &= ^= |=
- Comma operator:
,
Typing
Most operators serve several purposes in Pascal, for instance, the minus sign may be used for negation, subtraction, or set difference (depending on both type and syntactical context), the>=
operator may be used to compare numbers, strings, or sets, and so on. C uses dedicated operator symbols to a greater extent.Assignment and equality tests
The two languages use different operators for assignment. Pascal, like ALGOLALGOL
ALGOL is a family of imperative computer programming languages originally developed in the mid 1950s which greatly influenced many other languages and became the de facto way algorithms were described in textbooks and academic works for almost the next 30 years...
, uses the mathematical equality operator for equality test and the symbol
:=
for assignment, whereas C, like B uses the mathematical equality operator for assignment. In C (and B) the new
symbol was therefore introduced for equality test.It is a common mistake, either due to inexperience or a simple typing error, to accidentally put assignment expressions in conditional statements such as
if (a = 10) { ... }
. The code in braces will always execute because the assignment expression a = 10
has the value 10 ≠ 0 and is therefore considered "true" in C. Also note that a
now has the value 10
, which may affect the following code. Recent C compilers try to detect these cases and warn the user, asking for a less ambiguous syntax like if ((a=10) != 0 ) { ... }
. This kind of mistake cannot happen in Pascal, as assignments are not expressions; using the wrong operator will cause a compile error (and it's not likely that anyone would mistake the :=
symbol for equality test).Implementation issues
When Niklaus WirthNiklaus Wirth
Niklaus Emil Wirth is a Swiss computer scientist, best known for designing several programming languages, including Pascal, and for pioneering several classic topics in software engineering. In 1984 he won the Turing Award for developing a sequence of innovative computer languages.-Biography:Wirth...
designed Pascal, the desire was to limit the number of levels of precedence (fewer parse routines, after all). So the OR and exclusive OR operators are treated just like an Addop and processed at the level of a math expression. Similarly, the AND is treated like a Mulop and processed with Term. The precedence levels are
Level Syntax Element Operator
0 factor literal, variable
1 signed factor unary minus, NOT
2 term *, /, AND
3 expression +, -, OR
Notice that there is only ONE set of syntax rules, applying to both kinds of operators. According to this grammar, then, expressions like
x + (y AND NOT z) DIV 3
are perfectly legal. And, in fact, they are, as far as the parser is concerned. Pascal doesn't allow the mixing of arithmetic and Boolean variables, and things like this are caught at the semantic level, when it comes time to generate code for them, rather than at the syntax level.
The authors of C took a diametrically opposite approach: they treat the operators as different, and have something much more akin to our seven levels of precedence. In fact, in C there are no fewer than 15 levels. That's because C also has the operators '=', '+=' and its kin, '<<', '>>', '++', '--', etc. Although in C the arithmetic and Boolean operators are treated separately, the variables are not: a Boolean test can be made on any integer value. A strange consequence of this grammar is that every expression is potentially a Boolean expression.
Logical connectives
In Pascal a boolean expression that relies on a particular evaluation ordering (possibly via side-effects in function calls) is, more or less, regarded as an error. The Pascal compiler has the freedom to use whatever ordering it may prefer and must always evaluate the whole expression even if the result can be determined by partial evaluation.In C, dependence on boolean evaluation order is perfectly legal, and often systematically employed using the
&&
and ||
operators together with operators such as ++
, +=, the comma operator, etc. The &&
and ||
operators thereby function as combinations of logical operators and conditional statements.
Short circuit expression evaluation has been commonly considered an advantage for C because of the "evaluation problem":
var i: integer;
a: packed array [1..10] of char;
...
i := 1;
while (i <= 10) and (a[i] <> 'x') do i := i+1;
...
This seemingly straightforward search is problematic in Pascal because the array access a[i] would be invalid for i equal to 11.
However, in superscalar processors there is a penalty for all jumps because they cause pipeline stalls, and programs created for them are more efficient if jumps are removed where possible. Pascal's ability to evaluate using a fixed formula without jumps can be an advantage with highly optimizing compilers, whereas C has effectively prevented this by requiring short circuit optimization.
Control structures
Statements for building control structures are roughly analogous and relatively similar (at least the first three).
Pascal has:
- if cond then stmt else stmt
- while cond do stmt
- repeat stmt until cond
- for id := expr to expr do stmt and for id := expr downto expr do stmt
- case expr of expr : stmt; ... expr : stmt; else: stmt; end
C has:
- if (cond) stmt else stmt
- while (cond) stmt
- do stmt while (cond)
- for (expr; cond; expr) stmt
- switch (expr) { case expr : stmt; ... case expr : stmt; default: stmt }
Pascal, in its original form, did not have an equivalent to default, but an equivalent else clause is a common extension. Pascal programmers otherwise had to guard case-statements with an expression such as: if expr not in [A..B] then default-case.
C has the so called early-out statements break and continue, and some Pascals have them as well. There is controversy about whether the inclusion of these statements is in keeping with structured programming methodology. The best that can be said about this is that the use of break and continue may make programming easier, but there is no case where they cannot be replaced by "orthodox" structured programming constructs.
Both C and Pascal have a goto statement. However, since Pascal has nested procedures/functions, jumps can be done from an inner procedure or function to the containing one; this was commonly used to implement error recovery. C has this capability via the ANSI C setjmp and longjmp. This is equivalent, but arguably less safe, since it stores program specific information like jump addresses and stack frames in a programmer accessible structure.
Functions/procedures
Pascal routines that return a value are called functions; routines that don't return a value are called procedures. All routines in C are called functions; C functions that do not return a value are declared with a return type of "voidVoid typeThe void type, in several programming languages derived from C and Algol68, is the type for the result of a function that returns normally, but does not provide a result value to its caller. Usually such functions are called for their side effects, such as performing some task or writing to their...
".
Pascal procedures are considered equivalent to C "void" functions, and Pascal functions are equivalent to C functions that return a value.
The following two declarations in C:
int f(int x, int y);
void k(int q);
are equivalent to the following declarations in Pascal:
function f(x, y: integer): integer;
procedure k(q: integer);
Pascal has two different types of parameters: pass-by-value, and pass-by-reference (VAR).
function f(var k: integer): integer;
x := f(t);
As with Pascal, there are pass-by-value and pass-by-reference parameters in C. References are achieved using pointers. The following segment is similar to the Pascal segment above:
int f(int *k); //function accepts a pointer as parameter
x = f(&t);
C allows for functions to accept a variable number of parameters, known as variadic functionsVariadic functionIn computer programming, a variadic function is a function of indefinite arity, i.e., one which accepts a variable number of arguments. Support for variadic functions differs widely among programming languages....
.
int f(int a, ...);
f(1, 2, 3, 4, 5);
The function f
uses a special set of functions that allow it to access each of the parameters in turn. This set of functions was undefined in original C, but was defined in ANSI C.
Additionally Pascal has I/O statements built into the language to handle variable amount of parameters, like Writeln
. Pascal allows procedures and functions to be nestedNested functionIn computer programming, a nested function is a function which is lexically encapsulated within another function. It can only be called by the enclosing function or by functions directly or indirectly nested within the same enclosing function. In other words, the scope of the nested function is...
. This is convenient to allow variables that are local to a group of procedures, but not global. C does not have this feature and the localization of variables or functions could only be done for a compilation module wherein the variables or functions would have been declared static.
C allows functions to be indirectly invoked through a function pointer. In the following example, the statement (*cmpar)(s1, s2)
is equivalent to strcmp(s1, s2)
:
- include
int (*cmpar)(const char *a, const char *b);
const char *s1 = "hello";
const char *s2 = "world";
cmpar = &strcmp;
b = (*cmpar)(s1, s2);
Though, in this example, it would be wiser to use preprocessor statements to accomplish similar ends (unless cmpar
was set based upon run-time conditions, which cannot be handled by the preprocessor).
Pascal also allows functions and procedures to be passed as parameters to functions or procedures:
procedure ShowHex(i: integer);
...
end;
procedure ShowInt(i: integer);
...
end;
procedure Demo(procedure Show(i: integer));
var j: integer;
begin
Show(j)
end;
...
Demo(ShowHex);
Demo(ShowInt);
...
Preprocessor
Early C had neither constant declarations nor type declarations, and the C language was originally defined as needing a "preprocessorPreprocessorIn computer science, a preprocessor is a program that processes its input data to produce output that is used as input to another program. The output is said to be a preprocessed form of the input data, which is often used by some subsequent programs like compilers...
"; a separate program, and pass, that handled constant, include and macro definitions, in order to keep memory usage down. Later, with ANSI C, it obtained constant and type definitions features and the preprocessor also became part of the language itself, leading to the syntax we see today.
Pascal constant and type defines are built in, but there were programmers using a preprocessor also with Pascal (sometimes the same one used with C), certainly not as common as with C. Although often pointed out as a "lack" in Pascal, technically C doesn't have program modularity nor macros built in either. It has a simple low level separate compilation facility, however (traditionally using the same generic linker used for assembly language), Pascal does not.
Type escapes
C supports the ability to "cast" any type to another type. While some imply a conversion of some sort (truncation, promotion etc.), pointer casts allow the user to simply assume the desired type is pointed:
int *a;
float b;
a = (int*) &b;
The meaning of such casts is entirely machine dependent. This feature often helps with low level conversion of data. For example, a floating point value can be output to a file as a series of bytes.
It may be possible to do this in Pascal using an undiscriminated variant record:
var a: integer;
b: real;
a2c: record
case boolean of
false: (a: integer);
true: (b: real);
end;
end;
begin
a2c.b := b;
a := a2c.a;
end;
Although casting is possible on the most of Pascal compilers and interpreters, even in the code above a2c.a and a2c.b aren't required by any Pascal standardizations to share the same address space. Niklaus Wirth, the designer of Pascal, has written about the problematic nature of attempting type escapes using this approach:
"Most implementors of Pascal decided that this checking would be too expensive, enlarging code and deteriorating program efficiency. As a consequence, the variant record became a favourite feature to breach the type system by all programmers in love with tricks, which usually turn into pitfalls and calamities".
Several languages now specifically exclude such type escapes, for example Java, C# and Wirth's own Oberon.
Files
In C files do not exist as a built-in type (they are defined in a system header) and all I/O takes place via library calls. Pascal has file handling built into the language.
The typical statements used to perform I/O in each language are:
printf("The sum is: %d\n", x);
writeln('The sum is: ', x);
The main difference is that C uses a "format string" that is interpreted to find the arguments to the printf function and convert them, whereas Pascal performs that under the control of the language processor. The Pascal method is arguably faster, because no interpretation takes place, but the C method is highly extensible.
Later Pascal implementations and extensions
Some popular Pascal implementations have incorporated virtually all C constructs into Pascal. Examples include type casts, being able to obtain the address of any variable, local or global, and different types of integers with special promotion properties.
However, the incorporation of C's lenient attitude towards types and type conversions can result in a Pascal that loses some or all of its type security. For example, JavaJava (programming language)Java is a programming language originally developed by James Gosling at Sun Microsystems and released in 1995 as a core component of Sun Microsystems' Java platform. The language derives much of its syntax from C and C++ but has a simpler object model and fewer low-level facilities...
and C# were created in part to address some of the perceived type security issues of C, and have "managed" pointers that cannot be used to create invalid references. In its original form (as described by Niklaus WirthNiklaus WirthNiklaus Emil Wirth is a Swiss computer scientist, best known for designing several programming languages, including Pascal, and for pioneering several classic topics in software engineering. In 1984 he won the Turing Award for developing a sequence of innovative computer languages.-Biography:Wirth...
), Pascal qualifies as a managed pointer language, some 30 years before either Java or C#. However, a Pascal amalgamated with C would lose that protection by definition. In general, the lower dependence on pointers for basic tasks makes it safer than C in practice.
The Extended Pascal standard extends Pascal to support many things C supports, which the original standard Pascal did not, in a type safer manner. For example, schema types support (besides other uses) variable-length arrays while keeping the type-safety of mandatory carrying the array dimension with the array, allowing automatic run-time checks for out-of-range indices also for dynamically sized arrays.
Epilogue
It is difficult to produce a truly impartial comparison of C and Pascal, and even more difficult to avoid offending one or another language aficionado.
However, C and Pascal are similar languages, if you look at the basic program structures, data types and aims of the two languages. Each time a proponent of C claims that program X cannot be done in Pascal, someone else shows that it can be done and vice versa. A major difference between the languages is the handling of type security. Pascal has a better ability to detect type-related errors at compile time, but C allows more flexible handling of mixed data-types when that is what is required.
One of the limitations of original Pascal is the inability to specify dynamic arrays as procedure parameters, which even the creator of Pascal later agreed was not a good idea. Many years later Pascal compilers added an extension for that feature, and the ISO 7185 standard addressed it as well.
Although C was originally described as a "systems" or "low level" language, it is used for all types of applications including high level ones. Pascal, a language with an academic and educational background, did not gain long lasting support in industry in its original standardized form. However, the extended Pascal derivatives (e.g. Delphi) are in active use for all types of applications.
See also
- CC (programming language)C is a general-purpose computer programming language developed between 1969 and 1973 by Dennis Ritchie at the Bell Telephone Laboratories for use with the Unix operating system....
, C++
- Pascal, Object PascalObject PascalObject Pascal refers to a branch of object-oriented derivatives of Pascal, mostly known as the primary programming language of Embarcadero Delphi.-Early history at Apple:...
, Free PascalFree PascalFree Pascal Compiler is a free Pascal and Object Pascal compiler.In addition to its own Object Pascal dialect, Free Pascal supports, to varying degrees, the dialects of several other compilers, including those of Turbo Pascal, Delphi, and some historical Macintosh compilers...
, Delphi, Oxygene
- Pascal for C users
Further reading
- Kathleen Jensen and Niklaus Wirth: PASCAL - User Manual and Report. Springer-Verlag, 1974, 1985, 1991, ISBN 3540976493 http://www.cs.inf.ethz.ch/~wirth/books/Pascal/
- Brian KernighanBrian KernighanBrian Wilson Kernighan is a Canadian computer scientist who worked at Bell Labs alongside Unix creators Ken Thompson and Dennis Ritchie and contributed to the development of Unix. He is also coauthor of the AWK and AMPL programming languages. The 'K' of K&R C and the 'K' in AWK both stand for...
, Dennis RitchieDennis RitchieDennis MacAlistair Ritchie , was an American computer scientist who "helped shape the digital era." He created the C programming language and, with long-time colleague Ken Thompson, the UNIX operating system...
: The C Programming LanguageThe C Programming Language (book)The C Programming Language is a well-known programming book written by Brian Kernighan and Dennis Ritchie, the latter of whom originally designed and implemented the language, as well as co-designed the Unix operating system with which development of the language was closely intertwined...
. Also known as K&R — The original book on C.
- 1st, Prentice Hall 1978; ISBN 0-131-10163-3. Pre-ANSI C.
- 2nd, Prentice Hall 1988; ISBN 0-131-10362-8. ANSI C.
- Niklaus Wirth: Comment on a note on dynamic arrays in PASCAL 37-38, ACM SIGPLAN Notices, Volume 11, Issue 1, January 1976.
- Niklaus Wirth: Recollections about the Development of Pascal. 333-342, ACM SIGPLAN Notices, Volume 28, Issue 3, March 1993.
- ISO/IEC 9899. The official C:1999 standard, along with defect reports and a rationale.
- Detailed analysis of converting C to Pascal
- Alan R. Feuer, Narain H. Gehani: Comparison of the Programming Languages C and Pascal 73-92, ACM Computing Surveys, Volume 14, Issue 1, March 1982.
- Comparing and Assessing Programming Languages: Ada, C and Pascal, Ed. by Alan R. Feuer and Narain Gehani, Prentice Hall, 1984. ISBN 0-13-154840-9
- Scott Meyers: Effective C++, 2nd Ed., Addison-Wesley, 1998, ISBN 0-201-92488-9
- Vincent Hayward: Compared anatomy of the programming languages Pascal and C 50-60, ACM Sigplan Notices, Volume 21, Issue 5, May 1986.