Misplaced Pages

Comparison of Pascal and C: Difference between revisions

Article snapshot taken from[REDACTED] with creative commons attribution-sharealike license. Give it a read and then ask your questions in the chat. We can research this topic together.
Browse history interactively← Previous editContent deleted Content addedVisualWikitext
Revision as of 12:06, 16 December 2005 editMirror Vax (talk | contribs)5,609 edits rv, please stop screwing up categories which you evidently do not understand← Previous edit Latest revision as of 09:15, 19 November 2024 edit undoTocaTheFrog (talk | contribs)54 editsm Minor grammar errors fixedTags: Visual edit Newcomer task Newcomer task: references 
(686 intermediate revisions by more than 100 users not shown)
Line 1: Line 1:
{{Short description|Comparison of two programming languages}}
== C vs Pascal: A language comparison ==
{{Multiple issues|
{{more footnotes needed|date=June 2013}}
{{original research|date=September 2015}}
}}
{{ProgLangCompare}}
The computer ]s ] and ] have similar times of origin, influences, and purposes. Both were used to design (and compile) their own compilers early in their lifetimes. The original Pascal definition appeared in 1969 and a first compiler in 1970. The first version of C appeared in 1972.


] and ] are both arguably descendants of the ] ] series. ALGOL introduced so-called "]", where ] were constructed of single entry-single exit "components" such as "if", "while", "for", "case", etc. Also, whereas before ALGOL only the expression syntax for languages was described systematically, ALGOL defined the entire language in terms of a ] or grammar. This tended to make the language more general and regular. Both are descendants of the ] language series. ALGOL introduced programming language support for ], where programs are constructed of single entry and single exit constructs such as '''if''', '''while''', '''for''' and '''case'''. Pascal stems directly from ], while it shared some new ideas with ]. The C language is more indirectly related to ALGOL, originally through ], ], and ], and later through ALGOL 68 (for example in case of <code>struct</code> and <code>union</code>) and also Pascal (for example in case of enumerations, <code>const</code>, <code>]</code> and Booleans). Some Pascal dialects also incorporated traits from C.


The languages documented here are the Pascal of ], as standardized as ISO 7185 in 1982, and the C of ] and ], as standardized in 1989. The reason is that these versions both represent the mature version of the language, and also because they are comparatively close in time. ] and ] (the later C standards) features, and features of later implementations of Pascal (], ]) are not included in the comparison, despite the improvements in robustness and functionality that they conferred.
C and Pascal are often compared to each other, sometimes heatedly, probably
because the languages have similar times of origin, influences, and purposes,
and so represent two philosophical approaches to a similar need. Both languages
have roughly the same ]s, program structures and general layout. Both
were used to design their own ]s early in their lifetimes, and both
vied for superiority during the critical formative years of the early
] age. It is less interesting to compare, say, C with ]
or Pascal with ] because these languages are so clearly different,
with different aims.


== Identifiers == == Syntax ==
{{unreferenced section|date=June 2013}}
], Pascal is much more ALGOL-like than ]. English keywords are retained where C uses punctuation symbols – Pascal has <code>and</code>, <code>or</code>, and <code>mod</code> where C uses <code>&&</code>, <code>||</code>, and <code>%</code> for example. However, C is 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 ===
C and Pascal are almost identical with regard to ]s. All identifiers start with an alphabetical character, and continue with further alphabetical characters or digits. In C the character "_" (]) can also appear anywhere in the identifier, and identifiers that begin with "_" are considered system reserved, and are used to differentiate special system symbols from program symbols. Certain Pascal compilers use this naming scheme as well.
Another, more subtle, difference is the role of the ]. In Pascal, semicolons ''separate'' individual statements within a compound statement; instead in C, they ''terminate'' the statement. In C, they are also syntactically part of the statement (transforming an expression into a statement). This difference manifests mainly in two situations:


* in Pascal, a semicolon can never be directly before <code>else</code>, whereas in C, it is mandatory, unless a block statement is used
C and Pascal differ dramatically in their interpretation of upper and lower
* the last statement before an <code>end</code> or <code>until</code> is not required to be followed by a semicolon
case. In Pascal, case does not matter, in C it does. Thus:


A superfluous semicolon can be put on the last line before '''end''', thereby formally inserting an ''empty statement''.
MyLabel


=== Comments ===
and
In traditional C, there are only <code>/* block comments */</code>. This is only supported by certain Pascal dialects like MIDletPascal.


In traditional Pascal, there are <code>{ ''block comments'' }</code> and <code>(* ''block comments'' *)</code>.
mylabel
Modern Pascal, like Object Pascal (Delphi, FPC), as well as modern C implementations allow C++ style comments <code>// line comments</code>


=== Identifiers and keywords ===
are two different identifiers in C, but the same identifier in Pascal. This can cause problems if Pascal is used in a ] system primarily designed for C.
C and Pascal differ in their interpretation of upper and lower case. C is case sensitive while Pascal is not, thus <code>MyLabel</code> and <code>mylabel</code> 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 ] (words reserved for use by the language). 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.
== Keywords ==


=== Definitions, declarations, and blocks ===
Both C and Pascal use ]s, or words reserved for use by the language
In Pascal, ] definitions start with keywords '''procedure''' (no value returned) or '''function''' (a value is returned) and ] with '''type'''. In C, all subroutines have <code>function</code> definitions (procedures being <code>void function</code>s) and type definitions use the keyword <code>typedef</code>. 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 ]s are defined by the keyword <code>enum</code> in C but by punctuation in Pascal.
itself. Examples are "if", "while", "const", "for" and "goto", which are
also keywords that happen to be in common to both languages.


In Pascal subroutines, '''begin''' and '''end''' delimit a block of statements preceded by local declarations, while C functions use "{" and "}" to delimit a block of statements optionally preceded by declarations : C (before 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. By its syntax of a subroutine's body, Pascal enforces that declarations occur before statements. Pascal also allows ''definitions'' of types and functions{{snd}}not only variable declarations{{snd}} to be encapsulated by function definitions to any level of depth.
Pascal is often said to be "wordy" compared to C. In Pascal, blocks begin and end with "begin" and "end". C uses "{" and "}", respectively. In Pascal, a ] must begin with the keyword "function", a type with "type". In C, both of these are determined by context alone.


== Syntax == === 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 ] 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 <code>X * Y;</code> could be a declaration of <code>Y</code> to be an object whose type is pointer to <code>X</code>, or a statement-expression that multiplies <code>X</code> and <code>Y</code>. In contrast, the corresponding Pascal fragments <code>'''var''' Y : ^X;</code> and <code>Z := X * Y;</code> are inherently unambiguous; correct parsing does not require a symbol table.


== Simple types ==
C uses an abbreviated ] compared to Pascal. C is also context-sensitive. For example, an identifier used as a "struct" can be reused for other purposes in the program.
{{unreferenced section|date=June 2013}}


=== Integers ===
C was deliberately designed to take such shortcuts. The syntax is more compact as a result, but is more difficult to ], and has an irregular grammar.
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 type <code>int</code> (which corresponds to <code>]</code> 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 ] modes for integers by using modifiers such as <code>long</code>, <code>short</code>, <code>signed</code>, <code>unsigned</code>, etc. The exact meaning of the resulting integer type is machine-dependent, what ''can'' be guaranteed is that <code>long int</code> is no shorter than <code>int</code> and <code>int</code> is no shorter than <code>short int</code>. However, in C standard, there are at least minimal sizes of types are specified which guarantees <code>char</code> to be a single ] and <code>int</code> to be at least two bytes.
Pascal was designed to have a simple and regular syntax with only one context sensitivity, which is the assignment ambiguity:


=== Subranges ===
a := b;
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):


<syntaxhighlight lang="pascal">
where b could refer to a ] or a ].
type a = 1..100;
b = -20..20;
c = 0..100000;
</syntaxhighlight>


This subrange feature is not supported by C.
Because of the simplicity of parsing Pascal, it is often used in compiler training courses, and the parsers for Pascal-based languages are often very fast.


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 integer/subrange on the left hand side of the assignment. 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.
== Simple types ==


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.
In C, the default type is "int", which corresponds to "]" in Pascal. C
can ] many objects to be int by default, for example, the return type
of a function is int if not otherwise specified. However, this is considered
"old C" practice and rarely used today, and has been removed from the language as of C99. Pascal requires declaration of all
types.


Pre-Standard implementations of C as well as Small-C et al. allowed integer and ] types to be relatively freely intermixed.
C accommodates different sizes and ] modes for integers by
using modifiers such as long, signed, unsigned, etc. The exact meaning of
the resulting int type is machine-dependent. In Pascal, the same end is
performed by declaring a "subrange" of integer:


=== Character types ===
type a = 1..100;
In C the character type is <code>char</code> which is a kind of integer that is no longer than <code>short int</code>, . Expressions such as <code>'x'+1</code> are therefore perfectly legal, as are declarations such as <code>int i='i';</code> and <code>char c=74;</code>.
b = -20..20;
c = 0..100000;


This integer nature of <code>char</code> (one byte) is clearly illustrated by declarations such as
This subrange feature (simply called a "range") is not supported by C.
<syntaxhighlight lang="c">
unsigned char uc = 255; /* common limit */
signed char sc = -128; /* common negative limit */
</syntaxhighlight>


Whether the <code>char</code> type should be regarded as <code>signed</code> or <code>unsigned</code> by default is up to the implementation.
A major, if subtle, difference between C and Pascal is how they promote integer operations. In Pascal, all operations on integers or integer subranges must have the same effect as if all of the operands were promoted to a full integer. In C, there are defined rules as to how to promote different types of integers, typically with the effect that the result of two integers will not have a precision greater than either of the operands. This can have the effect of making C more efficient in use of registers or resources on a machine with mixed word lengths. A highly optimizing Pascal compiler can reduce, but not eliminate, the effect of this under standard Pascal rules. A side effect of this Pascal feature is that many Pascal compilers have special integer types and promotion rules.


In Pascal, characters and integers are distinct types. The inbuilt compiler functions <code>ord()</code> and <code>chr()</code> 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 <code>ord('1') = 49</code> and <code>chr(9)</code> is a TAB character.
In C, characters are interchangeable with ints. For example the following is
valid:


=== Boolean types ===
int a;
In Pascal, ''']''' is an enumerated type. The possible values of '''boolean''' are '''false''' and '''true''', with ordinal value of false&nbsp;=&nbsp;0 and true&nbsp;=&nbsp;1. For conversion to '''integer''', '''ord''' is used:
a = 'x'+1;


<syntaxhighlight lang="pascal">
In Pascal, char is a separate type from integer, and must be specifically
i := ord(b);
converted to integer with "ord". Likewise, a character is
</syntaxhighlight>
formed from an integer by the "chr" function.


There is no standard function for '''integer''' to '''boolean''', however, the conversion is simple in practice:
C formerly considered int and ] types to be the same, but this concept
proved problematic, especially in machines that had different sizes for the
two. In ANSI C, they are separate.


<syntaxhighlight lang="pascal">
== Character types ==
b := i <> 0;
</syntaxhighlight>


C has no ''']''' type. C uses binary valued relational operators (<, >, ==, !=, <=, >=) which may be regarded as ''Boolean'' in the sense that they always give results that 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. This is visible in the <code>bool</code> numeric datatype defined in <code>stdbool.h</code>.
C has no specific character type. The type char is actually a int that is
at least as small as, or smaller than "short int". Characters can be treated
as interchangeable with ints at any time:


==== Bitwise operations ====
x = x+'g';
C allows using ] ] to perform Boolean operations. Care must 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;
This integer form of characters in C is most clearly shown by the types:


Pascal:
signed char<br/>
<syntaxhighlight lang="pascal">
unsigned char
Status := Status + ;
Status := Status - ;
if (StickyFlag in Status) then ...


(* Alternatively, using bitwise operators: *)
Which are needed because char types are often used as "very short ints",
Status := Status or StickyFlag;
with no character value whatever.
Status := Status and not StickyFlag;
if StickyFlag and Status = StickyFlag then ...
</syntaxhighlight>


C:
In Pascal, character types are distinct types, and are rarely used as
<syntaxhighlight lang="c">
general integers. In order to convert character to integer, the function
Status |= StickyFlag;
"ord" must be used. In order to convert integer to character, the function
Status &= ~StickyFlag;
"chr" must be used.
if (Status & StickyFlag) { ...
</syntaxhighlight>


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.
== Boolean types ==


==== A note on implementation ====
C does not have a specific ] type, however, it does have Boolean operators, and operators that give Boolean results. A Boolean, like a character value, is an integer, and in fact, Booleans are usually stored to their most compact form in "char" types (since that often means a single byte on many machines). The relational operators give Boolean results, so "<", ">", "==" and others give Boolean results. A Boolean is stored as a "1" when true, or a "0" when false. However, tests for boolean truth are performed as a check for zero when false, and not zero when true. This means that int values greater than 1 can effectively be used for true values.
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 can use standard ] ] for Booleans, or special Boolean operators. For example, "|" is a bitwise OR, and "||" is a Boolean OR. In many cases, the effect is the same, however, this is not guaranteed. For example, ~0 (bitwise NOT 0) is not equal to 1, but usually -1 (on most computers). !0 (boolean NOT 0) is equal to 1. Therefore the programmer must pay attention to if the operands are intended for use as Boolean values or bit values.
C has a less strict model of ] 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 <code>real</code>, but conversion of <code>real</code> to <code>integer</code> (where information may be lost) must be done explicitly via the functions <code>trunc()</code> and <code>round()</code>, which ] or ] off the fraction, respectively.


=== Enumeration types ===
In Pascal, Boolean is an enumerated type. The values of Boolean, are "false" and "true". Just as in C they are stored as an integer value, but values greater than 1 are not valid. If Boolean is to be converted to integer, "ord" is used:
Both C and Pascal include enumeration types. A Pascal example:


<syntaxhighlight lang="pascal">
i := ord(b);
type
color = (red, green, blue);
var
a: color;
</syntaxhighlight>


A C example:
There is no language special function for integer to Boolean, however, the conversion is in
practice simple:


<syntaxhighlight lang="c">
b := i <> 0;
enum color {red, green, blue};
enum color a;
</syntaxhighlight>


The behavior of the types in the two languages however is very different. In Pascal enumerations are ordinal and parsed using <code>ord()</code>, <code>succ()</code> and <code>pred()</code> functions and are distinct from the <code>array</code> structure. In C, enumerations are in fact implemented as <code>arrays</code> and <code>red</code> becomes just a synonym for 0, <code>green</code> for 1, <code>blue</code> for 2, and nothing prevents a value outside this range to be assigned to the variable <code>a</code>. Furthermore, operations like <code>a = a + 1;</code> are strictly forbidden in Pascal; instead, you would use <code>a := succ(a);</code>. In C, enums can be freely converted to and from ints, but in Pascal, the function <code>ord()</code> must be used to convert from enumerated types to integers, in opposite conversion must be used typecast operation like <code>a := color(1)</code> for <code>green</code> value return.
== Real/floating point types ==


== Structured types ==
There is little difference between C and Pascal in ]/] types. In C, ints can be converted to floats, and vice versa, at will. In Pascal, integers can be converted to reals at will, but conversion of real to integer must be done via the functions "trunc" and "round", which ] or ] off the fraction, respectively.
{{Unreferenced section|date=June 2013}}


== Array types == === Array types ===
Both C and Pascal allow ]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:
<syntaxhighlight lang="c">
int a;
</syntaxhighlight>
and are always indexed from 0 up to SIZE&minus;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
Both C and Pascal allow ]s to be "structured", or consist of other complex
<syntaxhighlight lang="pascal">var a : array of integer;</syntaxhighlight>
types, including other arrays. However, there the similarity between the
would be indexed by 0..9 (just as in C in this case). Array indices can be any ], however, not just ranges:
languages ends. In C, arrays are declared by their number of elements:
<syntaxhighlight lang="pascal">
type
TColor = (red, green, blue); (* enumeration *)
RGB = array of 0..255;


var picture : array of RGB
int x;


var palette : array of byte
and the indexes are numbered from 0 to n, where n is the number of elements - 1.
</syntaxhighlight>
In Pascal, the starting and ending indexes are specified by a subrange
Strings consisting of n (>1) characters are defined as packed arrays with range 1..n.
(as introduced in "simple types" above):


==== Arrays and pointers ====
type x = array of integer;
In C expressions, an identifier representing an array is treated as a constant pointer to the first element of the array, thus, given the declarations <code>int a</code> and <code>int *p;</code> the assignment <code>p = a</code> is valid and causes p and a to point to the same array. As the identifier <code>a</code> represents a ''constant'' address, <code>a = p</code> 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.
Contrary to popular myth, this does not make Pascal arrays substantially
different from index than C arrays. For example:


In Pascal, arrays are a distinct type from pointers. This makes ] for arrays possible from a compiler perspective. Practically all Pascal compilers support range checking as a compile ''option''.
type x = array of integer;
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. (Note : since 1986 and Turbo Pascal 3, which was the industry standard, <code>GetMem()</code> allows dynamic arrays in everyday Pascal, if not in the ISO standard)


C has the ability to initialize arrays of arbitrary length. The <code>]</code> 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.
would be indexed as 0 to 9, just as in C.


<syntaxhighlight lang="c">
In Pascal, array indices can be any range type, even enumerations:
static char *wordlist = {
"print", "out", "the", "text", "message" };
static int listSize = (sizeof(wordlist)/sizeof(wordlist));
int i;


for (i=0; i<listSize; i++)
type
puts(wordlist);
enum = (red, green, blue);
for (i=listSize-1; i>=0; i--)
myarray = array of integer;
puts(wordlist);
</syntaxhighlight>


Likewise modern Pascal, e.g. Delphi and Free Pascal, has a similar ability. Initialized arrays can be implemented as:
In C, arrays are equivalent to a pointer with the same element type. Thus:
<syntaxhighlight lang="pascal">
var
wordlist: array of string = [
'print', 'out', 'the', 'text', 'message'];
i: Integer;
begin
for i := Low(wordlist) to High(wordlist) do
writeln(wordlist);
for i := High(wordlist) downto Low(wordlist) do
writeln(wordlist);
end.
</syntaxhighlight>


Original 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 original Pascal, but without the automatic size adjustment, is:
int *a;
int b


<syntaxhighlight lang="pascal">
can be used as:
const
minlist = 1;
maxlist = 5;
maxword = 7;


type
a = b;
listrange = minlist .. maxlist;
wordrange = 1..maxword;
word = record
contents: packed array of char;
length: wordrange
end;
wordlist = array of word;
var
i: integer;
words: wordlist;


procedure CreateList(var w: wordlist);
which causes a and b to point to the same array. Similarly:
begin
w.contents := 'print ';
w.length := 5;
w.contents := 'out ';
w.length := 3;
w.contents := 'the ';
w.length := 3;
w.contents := 'text ';
w.length := 4;
w.contents := 'message';
w.length := 7;
end;


begin
int *a;
CreateList(words);
for i := minlist to maxlist do
with words do
WriteLn(contents: length);
for i := maxlist downto minlist do
with words do
WriteLn(contents: length)
end.
</syntaxhighlight>


=== Strings ===
and
In both languages, a string is a primitive array of characters.


In Pascal a ] of length n is compatible with the type <code>packed array of char</code>. In C a string generally has the type <code>char</code>.
int b;


Pascal has no support for variable-length arrays, and so any set of routines to perform string operations is dependent on a particular string size. 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.
are both pointers to int.


C string literals are ]; that is to say, a trailing null character as an end-of-string ]:
The equivalence of C arrays and pointers suggests to programmers that
<syntaxhighlight lang="c">
arrays are "dynamic" or changing in length, for C. Actually, arrays in
const char *p;
C are fixed, but pointers to them are interchangeable. So for example:
p = "the rain in Spain"; /* null-terminated */
</syntaxhighlight>
Null-termination must be manually maintained for string variables stored in arrays (this is often partly handled by library routines).


C lacks built-in string or array assignment, so the string is not being transferred to p, but rather p is being made to point to the constant string in memory.
int *a, b;
a = b;


In Pascal, unlike C, the string's first character element is at index 1 and not 0 (leading it to be ]). This is because Pascal stores the length of the string at the 0th element of the character array. If this difference is not well understood it can lead to errors when ] or trying to interface ] generated by both languages.
declares a fixed length array of 10 ints, and defines b to be a (constant)
pointer to that. Then, a is equated to point to that same array.


] developer ], writing in '']'', would later refer to the victory of null-terminated strings over length-prefixed strings as "the most expensive one-byte mistake" ever.<ref>{{citation |last=Kamp |first=Poul-Henning |date=25 July 2011 |title=The Most Expensive One-byte Mistake |journal=ACM Queue |volume=9 |number=7 |pages=40–43 |doi=10.1145/2001562.2010365 |s2cid=30282393 |issn=1542-7730 |doi-access=free }}</ref>
This flexibility allows C to manipulate any length array using the same
code. However it also leaves the problem of how to find the exact length
of an array up to the programmer, which can cause memory access faults.


=== Record types ===
In Pascal, arrays are a distinct type from pointers. This makes ]
Both C and Pascal can declare "]" types. In C, they are termed "structures".
for arrays possible from a compiler perspective. Practically all Pascal compilers
<syntaxhighlight lang="c">
support range checking as a compile option.
struct a {
The ability to both have array that change length at runtime, and be able to check them under
int b;
language control, is often termed "dynamic arrays".
char c;
};
</syntaxhighlight>
<syntaxhighlight lang="pascal">
type a = record
b: integer;
c: char;
end;
</syntaxhighlight>


In Pascal, we can use the sentence "'''with''' ''name_of_record'' do" in order to use directly the fields of that record, like local variables, instead of write ''name_of_record''.''name_of_field''. Here there is an example:
== Strings ==
<syntaxhighlight lang="pascal">
type r = record
s: string;
c: char;
end;
var r1 : r;
begin
with r1 do begin
s := 'foo';
c := 'b';
end;
</syntaxhighlight>


There is no equivalent feature to '''with''' in C.
Both C and Pascal consider character ] to be a special case of an
array:


In C, the exact bit length of a field can be specified:
char a;
<syntaxhighlight lang="c">
struct a {
type a = packed array of char;
unsigned int b:3;
unsigned int c:1;
};
</syntaxhighlight>
How much storage is used depends on traits (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''':
In both languages, it is up to the programmer to determine the exact length of a character array. However, in C, the method of using a null character (zero) as a "sentinel" for the end of string is supported by the language in the special case of a constant string:
<syntaxhighlight lang="pascal">
type a = packed record
b: 0..7;
c: 0..1;
end;
</syntaxhighlight>
Both C and Pascal support records which can include different fields overlapping each other:
<syntaxhighlight lang="c">
union a {
int a;
float b;
};
</syntaxhighlight>
<syntaxhighlight lang="pascal">
type a = record
case boolean of
false: (a: integer);
true: (b: real)
end;
</syntaxhighlight>
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.
In Pascal, such constructs are called '''variant records''', not to be mistaken with the '''Variant''' datatype defined in Free Pascal.


The biggest difference between C and Pascal is that Pascal supports the ] for the language processor to determine if the valid component of the variant record is being accessed:
char *a;
<syntaxhighlight lang="pascal">
type a = record
a = "the rain in spain";
case q: boolean of
false: (a: integer);
true: (b: real)
end;
</syntaxhighlight>
In this case, the tag field q must be set to the right state to access the proper parts of the record.


== Pointers ==
In this case, the C language processor automatically adds the null to the
In C, pointers can be made to point at most program entities, including objects or functions:
end of the constant string, so that the end can be found.


<syntaxhighlight lang="c">
Pascal also supports the use of string constants for the special case of
int a;
a packed array whose starting index is 1:
int *b;

int (*compare)(int c, int d);
type string = packed array of char;
int MyCompare(int c, int d);
var a: string;
b = &a;
a := 'the rain in spain ';
compare = &MyCompare;
</syntaxhighlight>


In C, since arrays and pointers have a close equivalence, the following are the same:
However, Pascal leaves it entirely up to the programmer how to detect the
end of a string. The most common method is to pad strings on the right side,
but this is purely a programmer convention (many Pascal implementations
have dynamic strings as a language extension).


<syntaxhighlight lang="c">
C does not have built in string assignment. In the code:
a = b;
a = *(b+5);
a = *(5+b);
a = 5;
</syntaxhighlight>


Thus, pointers are often used in C as just another method to access arrays.
char *a;
a = "the rain in spain";


To create dynamic data, the library functions <code>malloc()</code> and <code>free()</code> are used to obtain and release dynamic blocks of data. Thus, ] 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.
the string is not actually being transferred to a, but rather a is being made
to point to the constant string in memory.


Pascal has the same kind of pointers as C, through the <code>^</code> referencing operator instead of the <code>*</code> of C. Each pointer is bound to a single dynamic data item, and can only be moved by assignment:
Pascal does have string (and in fact, all structured type) assignment, however,
the constant must match the type exactly:


<syntaxhighlight lang="pascal">
type string = packed array of char;
type a = ^integer;
var a: string;
a := 'the rain in spain ';


var b, c: a;
Thus constant strings must be padded out to force type equality. This, along
with the general lack of dynamic string support, is considered to be a problem
with the language.


new(b);
== Record types ==
c := b;
</syntaxhighlight>


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 ] issues and platform-independent type sizes) is not permitted in Pascal.
Both C and Pascal can declare ] types. In C, they are termed "structures".
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 of.


== Expressions ==
struct a {
{{unreferenced section|date=June 2013}}
int b;
char c;
};


=== Precedence levels ===
type a = record
The languages differ significantly when it comes to expression evaluation, but all-in-all they are comparable.
b: integer;
c: char
end;


{{warning|Incomplete list of Pascal operators (e.g. '''shl''', '''shr''', '''xor''', '''SizeOf''', '''Inc''', '''Dec''' are missing). This list needs to be completed.}}
In C, the exact bit length of a field can be specified:


''Pascal''
struct a {
# ''Logical negation:'' <code>'''not'''</code>
# ''Multiplicative:'' <code>'''* / div mod and'''</code>
int b:3;
# ''Additive:'' <code>'''+ - or'''</code>
int c:1;
# ''Relational:'' <code>'''= <> < > <= >= in'''</code>
};


''C''
Contrary to popular opinion, this can also be done in Pascal by using the subrange construct:
# ''Unary postfix:'' <code>''' () . -> ++ --'''</code>
# ''Unary prefix:'' <code>'''& * + - ! ~ ++ -- (type) ]'''</code>
# ''Multiplicative:'' <code>'''* / %'''</code>
# ''Additive:'' <code>'''+ -'''</code>
# ''Shift:'' <code>'''<< >>'''</code>
# ''Relational:'' <code>'''< > <= >='''</code>
# ''Equality:'' <code>'''== !='''</code>
# ''Bitwise and:'' <code>'''&'''</code>
# ''Bitwise xor:'' <code>'''^'''</code>
# ''Bitwise or:'' <code>'''|'''</code>
# ''Logical and:'' <code>'''&&'''</code>
# ''Logical or:'' <code>'''||'''</code>
# ''Conditional:'' <code>'''? :'''</code>
# ''Assignment:'' <code>'''= += -= *= /= %= <<= >>= &= ^= |='''</code>
# ''Comma operator'': <code>''','''</code>


=== Typing ===
type a = record
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 <code>&gt;=</code> operator may be used to compare numbers, strings, or sets, and so on. C uses dedicated operator symbols to a greater extent.
b: 0..3;
c: 0..1
end;


==== Assignment and equality tests ====
However, the compiler must support packing of records to the bit level.
The two languages use different operators for assignment. Pascal, like ], uses the mathematical equality operator <code>=</code> for the equality test and the symbol <code>:=</code> for assignment, whereas C, like ], uses the mathematical equality operator for assignment. In C (and B) the <code>==</code> symbol of ] was chosen for the equality test.


It is a common mistake in C, due either to inexperience or to a simple typing error, to accidentally put assignment expressions in conditional statements such as {{c-lang|1=if (a = 10) { ... } }}. The code in braces will always execute because the assignment expression <code>a = 10</code> has the value 10 which is non-zero and therefore considered "true" in C; this is in part because C (and ALGOL) allow multiple assignment in the form <code>a = b = c = 10;</code> which is not supported by Pascal. Also note that <code>a</code> now has the value <code>10</code>, 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 {{c-lang|1=if ((a=10) != 0 ) { ... } }}.
Both C and Pascal can have records which have different fields overlapping
each other:


This kind of mistake cannot happen in Pascal, as assignments are not expressions and do not have a value: using the wrong operator will cause an unambiguous compilation error, and it's also less likely that anyone would mistake the <code>:=</code> symbol for an equality test.
union a {
int a;
float b;
};


It is notable that ALGOL's conditional expression in the form {{code|2=pascal|1=z := if a > b then a else b;}} has an equivalent in C (the ]) but not in Pascal, which will use {{code|2=pascal|1=if a > b then z:=a; else z:=b;}}.
type a = record
case boolean of
false: (a: integer);
true: (b: real)
end;


===Implementation issues===
Both language processors are free to allocate only as much space for
When ] 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
these records as needed to contain the largest type in the union/record.
{{aligned table|cols=3|row1header=y|class=wikitable
| Level | Syntax Element | Operator
<!------------------------------------------------------------>
| 0 | factor | literal, variable
| 1 | signed factor | unary minus, {{tt|NOT}}
| 2 | term | {{tt|*, /, AND}}
| 3 | expression | {{tt|+, -, OR}}
}}
Notice that there is only ONE set of syntax rules, applying to both kinds of operators. According to this grammar, then, expressions like
<pre>
x + (y AND NOT z) / 3
</pre>
are perfectly legal. And, in fact, they are, as far as the parser is concerned. Pascal does not 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 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.
The biggest difference between C and Pascal is that Pascal allows the
use of a "tagfield" for the language processor to determine if the valid
component of the variant record is being accessed:


==== Logical connectives ====
type a = record
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. (Note: since Turbo Pascal 3 (1986) the short-circuit Boolean evaluation is available in everyday Pascal, if not in the ISO standard).
case q: boolean of
false: (a: integer);
true: (b: real)
end;


In C, dependence on ''boolean'' evaluation order is perfectly legal, and often systematically employed using the <code>&&</code> and <code>||</code> operators together with operators such as <code>++</code>, <code>+=</code>, the comma operator, etc. The <code>&&</code> and <code>||</code> operators thereby function as combinations of logical operators and conditional ''statements''.
In this case, the tagfield q must be set to the right state to access the
proper parts of the record.


Short circuit expression evaluation has been commonly considered an advantage for C because of the "evaluation problem":
C, in its original version, cannot assign structs or pass them to functions,
<syntaxhighlight lang="pascal">
but Pascal can. This capability was added to C in C99.
var i: integer;
a: packed array of char;
...
i := 1;
while (i <= 10) and (a <> 'x') do i := i+1;
...
</syntaxhighlight>
This seemingly straightforward search is problematic in Pascal because the array access a would be invalid for i equal to 11.
There is more than one way to avoid this problem. The following example introduces a Boolean variable which indicates whether or not the target character has been found:
<syntaxhighlight lang="pascal">
const
strlen = 10;
var i: integer;
a: packed array of char;
found: boolean;
...
i := 1;
found := false;
while not found and (i <= strlen) do
if (a = 'x') then found := true else i := i+1;
...
</syntaxhighlight>
Alternatively, the test for end of array can be separated from the array access and a goto statement can break out of the search if the target is found:
<syntaxhighlight lang="pascal">
label 99;
const
strlen = 10;
var i: integer;
a: packed array of char;
...
i := 1;
repeat
if a = 'x' then goto 99;
i := i+1
until i > strlen;
99:
...
</syntaxhighlight>


== Pointers == == Control structures ==
Statements for building control structures are roughly analogous and relatively similar (at least the first three).
{{aligned table|cols=2|row1header=y|class=wikitable
| 1=Pascal
| 3= <code>'''if''' ''cond'' '''then''' ''stmt'' '''else''' ''stmt''</code>
| 5= <code>'''while''' ''cond'' '''do''' ''stmt''</code>
| 7= <code>'''repeat''' ''stmt'' '''until''' ''cond''</code>
| 9= <code>'''for''' ''id'' := ''expr'' '''to''' ''expr'' '''do''' ''stmt''</code><br/>and<br /><code>'''for''' ''id'' := ''expr'' '''downto''' ''expr'' '''do''' ''stmt''</code>
|11= <code>'''case''' ''expr'' '''of'''<br/>{{quad}}''expr'' ''':''' ''stmt'';<br/>{{quad}}...<br/>{{quad}}''expr'' ''':''' ''stmt'';<br/>{{quad}}'''else:''' ''stmt'';<br/>'''end'''</code>
| 2=C
| 4= <code>'''if''' (''cond'') ''stmt'' '''else''' ''stmt''</code>
| 6= <code>'''while''' (''cond'') ''stmt''</code>
| 8= <code>'''do''' ''stmt'' '''while''' (''cond'');</code>
|10= <code>'''for''' (''expr''; ''cond''; ''expr'') ''stmt''</code>
|12= <code>'''switch''' (''expr'') {<br/>{{quad}}'''case''' ''expr'' ''':''' ''stmt'';<br/>{{quad}}...<br/>{{quad}}'''case''' ''expr'' ''':''' ''stmt'';<br/>{{quad}}'''default:''' ''stmt''<br/>}</code>
}}
Pascal, in its original form, did not have an equivalent to {{tt|default}}, but an equivalent <code>else</code> clause is a common extension. Pascal programmers otherwise had to guard case-statements with an expression such as: {{mono|'''if''' ''expr'' '''not''' '''in''' '''then''' ''default-case''}}.


C has the so-called early-out statements {{tt|break}} and {{tt|continue}}, and some Pascals have them as well.
In C, pointers can be made to point at most program objects, even constant
objects:


Both C and Pascal have a {{tt|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 ability via the ANSI C ]. This is equivalent, but arguably less safe, since it stores program specific information like jump addresses and stack frames in a programmer accessible structure.
int a;
int *b;
b = &a;


== Functions and procedures ==
In C, since arrays and pointers are equivalent, the following are the same:
Pascal routines that return a value are called functions; routines that do not 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 '']''.


Pascal procedures are considered equivalent to C "void" functions, and Pascal functions are equivalent to C functions that return a value.
a = b;
a = *(b+5);


The following two declarations in C:
Thus, pointers are often used in C as just another method to access arrays.
<syntaxhighlight lang="c">
int f(int x, int y);
void k(int q);
</syntaxhighlight>


are equivalent to the following declarations in Pascal:
To create dynamic data, the library functions "malloc" and "free" are used
<syntaxhighlight lang="pascal">
to obtain and release dynamic blocks of data. Thus, ] is
function f(x, y: integer): integer;
not built into the language processor.
procedure k(q: integer);
</syntaxhighlight>


Pascal has two different types of parameters: pass-by-value, and pass-by-reference (VAR). In both cases the variable name is used when calling (no need of address operator).
In Pascal, pointers are much more restricted. Each pointer is bound to a
<syntaxhighlight lang="pascal">
single dynamic data item, and can only be moved by assignment:
function f(z: integer; var k: integer): integer; // function accepts two integers, one by value, one by reference
Begin
z:=1; // outer variable u will not be modified, but local value is modified in the function's scope
k:=1; // outer variable t will be modified because it was passed by reference
// up to here, z exists and equals 1
End;


x := f(u,t); // the variables u and t are passed to the call : the value of u and the reference to t
type a = ^integer;
</syntaxhighlight>
var b, c: a;
new(b);
c := b;


In C all parameters are passed by value but pass-by-reference can be simulated using pointers. The following segment is similar to the Pascal segment above:
In Pascal, pointers can never point to program objects such as variables.
This tends to make Pascal more type safe than C, but not completely type
safe. Pascal can still have invalid pointer references in several ways.
For example, a pointer can be referenced when uninitialized, or it would
be referenced after it is disposed, etc.


<syntaxhighlight lang="c">
== Statements ==
int f(int z, int *k) { //function accepts an int (by value) and a pointer to int (also by value) as parameter
z=1; // idem Pascal, local value is modified but outer u will not be modified
*k=1; // variable referenced by k (eg, t) will be modified
// up to here, z exists and equals 1
}


x = f(u,&t); // the value of u and the (value of) address of variable t are passed to the call
The statements used between C and Pascal are roughly analogous.
</syntaxhighlight>


One of the most important difference between C and Pascal is the way they handle the parameters on stack during a subroutine call :
if (x) ... else ...
This is called the '''calling convention''' :
PASCAL-style parameters are pushed on the stack in left-to-right order.
while (x) ...
The STDCALL calling convention of C pushes the parameters on the stack in right-to-left order.
do ... while (x) ...
switch (x) { case a: ...; case b: ...; default: }


Pascal-style procedure call is made with :
if x then ... else ...
* caller pushing parameters into the stack in left-to-right order (opposite of {{tt|__cdecl}})
* calling the function
while x do ...
* stack is cleaned up by the callee
repeat ... until x
case x of a: ...; b: ... end


<syntaxhighlight lang="nasm">
Pascal, in its original form, did not have an equivalent version of
; example of pascal-style call.
"default" case (this is a common extension).
; NOTE: __stdcall would push the arguments in reverse order.
push arg1
push arg2
push arg3
call function
; no stack cleanup upon return: callee did it
</syntaxhighlight>
The advantage of PASCAL call over STDCALL is that the code is slightly smaller, though the size impact is only visible in large programs, and that recursion works faster.


Variadic functions are almost impossible to get right with PASCAL and STDCALL methods, because only the caller really knows how many arguments were passed in order to clean them up.
C has so called "early out" statements "break" and "continue". Pascal
does not. 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.


C allows for functions to accept a variable number of parameters, known as ]s, using a clumsy mechanism of <code>va_list ap;</code>, <code>va_start(ap, count);</code>, <code>va_arg(ap, ''type'');</code> with limited ''type'' availability (example : nothing for <code>bool</code>)
Both C and Pascal have a "goto" statement. However, Pascal allows jumps
between different procedures or functions, which is commonly used to
implement error recovery. C has this capability via the ANSI C
]. This is equivalent, but a little more difficult
to use, because you must arrange for the setjmp to be executed both
before the jump is executed, and when the jump is executed.


<syntaxhighlight lang="c">
Both C and Pascal use ";" between statements. However, C always terminates
int f(int a, ...);
statements with ";", but Pascal considers it a separator. In practice, there
f(1, 2, 3, 4, 5);
is little difference between these styles.
</syntaxhighlight>


The function <code>f()</code> uses a special set of functions (<code>varargs</code>) that allow it to access each of the parameters in turn.
In C, comments are formed by /* comment */. In Pascal, it is (* comment *) or
{ comment }.


Pascal and C also have some variadic I/O functions, for instance <code>WriteLn()</code> and <code>printf()</code>.
== Functions/Procedures ==


Modern Pascals enable a variable number of parameters for functions :
In Pascal, routines that return a value are called functions, and routines that don't return a value are called procedures. In C all routines are called functions, however routines that do not return a value are declared to return "void", meaning that they do not return anything. Actually "void" is not really a valid variable type, it can only be used when declaring the return type of a function. It cannot be used for declaring normal variables of this type, for example.
<syntaxhighlight lang="pascal">
procedure writeLines(const arguments: array of const); // parsed via : for argument in arguments do
</syntaxhighlight>
They also enable to interface with varargs C functions :
<syntaxhighlight lang="pascal">
Function PrintF1(fmt : pchar); cdecl; varargs; external 'c' name 'printf';
</syntaxhighlight>


Pascal allows procedures and functions to be ]. This is convenient to allow variables that are local to a group of procedures, but not global. C lacks this feature and the localization of variables or functions can be done only for a compiling module wherein the variables or functions would have been declared '''static'''.
In practice Pascal procedures are equivalent to C functions that return "void", and Pascal functions are equivalent to C functions that return a non-void type.


C and Pascal allow functions to be indirectly invoked through a ]. In the following example, the statement <code>(*cmpar)(s1, s2)</code> is equivalent to <code>strcmp(s1, s2)</code>:
The following two declarations in C:
int f(int x, int y);
void k(int q);


<syntaxhighlight lang="c">
are equivalent to the following declarations in Pascal:
#include <string.h>
function f(x, y: integer): integer;
procedure k(q: integer);


int (*cmpar)(const char *a, const char *b);
In Pascal, there are two different types of parameters, value and pass by
const char *s1 = "hello";
reference or VAR parameters. In C, there are only value parameters, but the
const char *s2 = "world";
C ability to point to any variable allows the programmer to construct their
own pass by reference scheme:


cmpar = &strcmp;
int f(int *k);
b = (*cmpar)(s1, s2);
</syntaxhighlight>
x = f(&t);


In Pascal functions and procedures can be passed as parameters to functions or procedures:
function f(var k: integer): integer;
<syntaxhighlight lang="pascal">
procedure ShowHex(i: integer);
x := f(t);
...
end;


procedure ShowInt(i: integer);
In C, it is possible to create a function with any number of parameters:
...
end;


procedure Demo(procedure Show(i: integer));
int f(int a, ...);
var j: integer;
begin
f(1, 2, 3, 4, 5);
Show(j)
end;


...
The function f uses a special set of functions that allow it to access
Demo(ShowHex);
each of the parameters in turn. This set of functions was undefined in
Demo(ShowInt);
original C, but was defined in ANSI C. In practice, this feature is
...
easy to call to, but fairly complex, and was machine dependent, to create
</syntaxhighlight>
functions that are called using it. Perhaps because of this, it is mainly
used to form the language support library for C, specifically I/O.

Pascal has no equivalent to C's n-parameter feature. However, Pascal
has I/O statements built-in to the language, so there is less need for it.

Pascal allows procedures and functions to be nested:

procedure a;
procedure b;
begin
end;
begin
end;

This is convenient to allow variables that are local to a group of procedures,
but not global.

C did not have this feature until C99.


== Preprocessor == == Preprocessor ==
Early C had neither constant declarations nor type declarations, and the C language was originally defined as needing a "]"; a separate program, and pass, that handled constant, include and ] definitions, 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, leading to the syntax we see today.


Pascal constant and type defines are built in and don't need a preprocessor.
The C language was originally defined as needing a "]", which was
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 does not 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.
a separate pass that handled constant, type, include and ] definitions.
This was required since the first C didn't have either constant declarations
nor type declarations. However, C obtained those features later with
ANSI C.

Pascal wasn't defined with a preprocessor, but several programmers did use
it with a preprocessor, sometimes the same one that was used with C. It
certainly was not as common as preprocessor use with C, but Pascal had
constant and type defines, so the remaining use for the preprocessor was
include files and macros.

Although this is often pointed at as a "lack" in Pascal, technically
C didn't have program modularity nor Macros built in either, and both
languages could just as well be equipped with a preprocessor.

As a practical matter, most of the succeeding versions of Pascal used
a type controlled modular method instead of include files, so the need
for a preprocessor is largely redundant.


== Type escapes == == Type escapes ==
In C, the programmer may inspect the byte-level representation of any object by pointing a <code>char</code> pointer to it:
<syntaxhighlight lang="c">
int a;
char *p = (char *)(&a);
char c = *p; // first byte of a
</syntaxhighlight>


It may be possible to do something similar in Pascal using an undiscriminated variant record:
C, in keeping with its loose typing requirements, features the ability to
<syntaxhighlight lang="pascal">
"cast" a type to become another:
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;
</syntaxhighlight>
Although casting is possible on most Pascal compilers and interpreters, even in the code above a2c.a and a2c.b are not 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".
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 ] as a series of ]s.

Again contrary to popular opinion, Pascal can also do this, with a considerably
more complicated method:

var a: integer;
b: real;
a2c: record
case boolean of
false: (a: integer);
true: (b: real);
end;
begin
a2c.b := b;
a := a2c.a;
end;


Several languages now specifically exclude such type escapes, for example Java, C# and Wirth's own ].
In Pascal, such type conversions are discouraged, hence the difficulty.


== Files == == 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.

In C, there are actually no files at all. This capability is left up to the
programmer. This is in keeping with ALGOL, which left the I/O capabilities
of the language up to the specific installation.

In practice, a large library of standard file access features is available
with C, so this is not an issue.

Pascal has files built into the language.


The typical statements used to perform I/O in each language are: The typical statements used to perform I/O in each language are:


:<syntaxhighlight lang="c">
printf("The sum is: %d\n", x);
printf("The sum is: %d\n", x);
</syntaxhighlight>


:<syntaxhighlight lang="pascal">
writeln('the sum is: ', x);
writeln('The sum is: ', x);
</syntaxhighlight>


The main difference is that C uses a "format string" that is interpreted to 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.
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.


== "Blue Sky" Pascal == == Later Pascal implementations and extensions ==
Some popular Pascal implementations have incorporated virtually all C constructs into Pascal. Examples include type casts,<ref>{{Cite web |title=Typecast - Lazarus wiki |url=https://wiki.freepascal.org/Typecast |access-date=2024-05-18 |website=wiki.freepascal.org}}</ref> 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, ] and ] 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 ]), 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.
In commenting on Pascal vs. C, it is certainly germane to mention that some popular Pascal implementations have removed virtually all differences with C by incorporating C methods and contructs into Pascal. Examples include type casts, being able to "coin" a pointer to any variable, local or global, and different types of integers with special promotion properties.


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.
These weren't discussed here because those implementations basically reduce the question of "what is the difference between C and Pascal?" to the answer "none". This is certainly one important technique towards achieving a "universal" Pascal. In fact, many popular Pascal implementations are, in fact, an amagamation of the languages Pascal, C and Basic, the last being because strings are extensively supported, even though neither original Pascal nor C has such support.


== See also ==
However, in languages it is not true that you can have your cake and eat it too. The incorporation of C's cavalier attitude towards types and type convertions can result in a Pascal that loses the type security of original Pascal. For example, Java and C# were created to address some of the 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 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.
* ], ]
* ], ], ], ], ]
* ]


== Epilogue == == Notes ==
{{reflist}}

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 extraordinarily similar languages, if you look at
the basic program structures, data 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. Each time a proponent of Pascal claims that
program Y cannot be made machine independent in C, someone else shows that
this, too, can be done.

About the only fault with Pascal that everyone agrees on is the lack of
dynamic arrays, which even the creator of Pascal later agreed was not a
good idea. Many, or even most later Pascal compilers added an extension
for that problem, and the ISO 7185 standard addressed it as well.

The remaining major difference between the languages that everyone agrees
on is type security. This is neither the runaway emergency for C that
many claim (you can program array checks in C, you just have to do it
yourself), nor the massive lack for Pascal (you can escape types in
Pascal, it is just made painful on purpose).

Although Pascal is sometimes described as the "bondage" language, many
people can and do use it to construct systems and low level ]s.

Although C was originally described as a "systems" or "low level" language,
it is clearly used for all applications, including high level ones.


== Further reading == == Further reading ==
* ] and Niklaus Wirth: ''PASCAL - User Manual and Report.'' Springer-Verlag, 1974, 1985, 1991, ISBN 0-387-97649-3 and ISBN 0-540-97649-3 * ] and Niklaus Wirth: ''PASCAL - User Manual and Report.'' Springer-Verlag, 1974, 1985, 1991, {{ISBN|3-540-97649-3}} https://web.archive.org/web/20050314152247/http://www.cs.inf.ethz.ch/~wirth/books/Pascal/]
* ], ]: '']''. Also known as K&amp;R &mdash; The original book on C. * ], ]: '']''. Also called K&R the original book on C.
**1st, Prentice Hall 1978; ISBN 0-131-10163-3. Pre-ANSI C. ** 1st, Prentice Hall 1978; {{ISBN|0-13-110163-3}}. Pre-ANSI C.
**2nd, Prentice Hall 1988; ISBN 0-131-10362-8. ANSI C. ** 2nd, Prentice Hall 1988; {{ISBN|0-13-110362-8}}. ANSI C.
* Niklaus Wirth: 37-38, ACM SIGPLAN Notices, Volume 11, Issue 1, January 1976.
* Niklaus Wirth: 333-342, ACM SIGPLAN Notices, Volume 28, Issue 3, March 1993.
* . The official C:1999 standard, along with defect reports and a rationale. * . The official C:1999 standard, along with defect reports and a rationale.
*
*Alan R. Feuer, Narain H. Gehani: 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: 50-60, ACM SIGPLAN Notices, Volume 21, Issue 5, May 1986.
* in the FreePascal Compiler Wiki


{{Pascal programming language family}}
== See also ==
{{CProLang}}
*]
*]

<br>

{{Major programming languages small}}

]
]
]


{{DEFAULTSORT:Pascal and C comparison}}
]
]
]
] ]
] ]
] ]
] ]
]
]
]
]
]
]
]
]
]
]
]
]
]
]
]
]
]
]
]
]
]
]
]
]
]
]

Latest revision as of 09:15, 19 November 2024

Comparison of two programming languages
This article has multiple issues. Please help improve it or discuss these issues on the talk page. (Learn how and when to remove these messages)
This article includes a list of general references, but it lacks sufficient corresponding inline citations. Please help to improve this article by introducing more precise citations. (June 2013) (Learn how and when to remove this message)
This article possibly contains original research. Please improve it by verifying the claims made and adding inline citations. Statements consisting only of original research should be removed. (September 2015) (Learn how and when to remove this message)
(Learn how and when to remove this message)
Comparison of
programming languages

Comparison of individual
languages

The computer programming languages 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. 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 programming language support for 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 traits from C.

The languages documented here are the Pascal of Niklaus Wirth, as standardized as ISO 7185 in 1982, and the C of Brian Kernighan and Dennis Ritchie, as standardized in 1989. The reason is that these versions both represent the mature version of the language, and also because they are comparatively close in time. ANSI C and C99 (the later C standards) features, and features of later implementations of Pascal (Turbo Pascal, Free Pascal) are not included in the comparison, despite the improvements in robustness and functionality that they conferred.

Syntax

This section does not cite any sources. Please help improve this section by adding citations to reliable sources. Unsourced material may be challenged and removed. (June 2013) (Learn how and when to remove this message)

Syntactically, Pascal is much more ALGOL-like than C. English keywords are retained where C uses punctuation symbols – Pascal has and, or, and mod where C uses &&, ||, and % for example. However, C is 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 semicolon. In Pascal, semicolons separate individual statements within a compound statement; instead in C, they terminate the statement. In C, they are also syntactically part of the statement (transforming an expression into a statement). This difference manifests mainly in two situations:

  • in Pascal, a semicolon can never be directly before else, whereas in C, it is mandatory, unless a block statement is used
  • the last statement before an end or until 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 // line comments

Identifiers and keywords

C and Pascal differ in their interpretation of upper and lower case. C is case sensitive while Pascal is not, thus MyLabel 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 keywords (words reserved for use by the language). 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, subroutine definitions start with keywords procedure (no value returned) or function (a value is returned) and type definitions with type. In C, all subroutines have function definitions (procedures being void functions) and type definitions use the keyword typedef. 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 enumerations are defined by the keyword enum in C but by punctuation in Pascal.

In Pascal subroutines, begin and end delimit a block of statements preceded by local declarations, while C functions use "{" and "}" to delimit a block of statements optionally preceded by declarations : C (before 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. By its syntax of a subroutine's body, Pascal enforces that declarations occur before statements. Pascal also 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 parse 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. In contrast, the corresponding Pascal fragments var Y : ^X; and Z := X * Y; are inherently unambiguous; correct parsing does not require a symbol table.

Simple types

This section does not cite any sources. Please help improve this section by adding citations to reliable sources. Unsourced material may be challenged and removed. (June 2013) (Learn how and when to remove this message)

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 type int (which corresponds to integer 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 modes for integers by using modifiers such as long, short, signed, unsigned, etc. The exact meaning of the resulting integer type is machine-dependent, what can be guaranteed is that long int is no shorter than int and int is no shorter than short int. However, in C standard, there are at least minimal sizes of types are specified which guarantees char to be a single byte and int to be at least two bytes.

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 integer/subrange on the left hand side of the assignment. 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.

Pre-Standard implementations 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 is char 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 (one byte) is clearly illustrated by declarations such as

unsigned 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, boolean is an enumerated type. The possible values of boolean are false and true, with ordinal value of false = 0 and true = 1. 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 no Boolean type. C uses binary valued relational operators (<, >, ==, !=, <=, >=) which may be regarded as Boolean in the sense that they always give results that 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. This is visible in the bool numeric datatype defined in stdbool.h.

Bitwise operations

C allows using bitwise operators to perform Boolean operations. Care must 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 + ;
Status := Status - ;
if (StickyFlag in Status) then ...
(* Alternatively, using bitwise operators: *)
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 point 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 truncate or round 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 Pascal enumerations are ordinal and parsed using ord(), succ() and pred() functions and are distinct from the array structure. In C, enumerations are in fact implemented as arrays and 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, in opposite conversion must be used typecast operation like a := color(1) for green value return.

Structured types

This section does not cite any sources. Please help improve this section by adding citations to reliable sources. Unsourced material may be challenged and removed. (June 2013) (Learn how and when to remove this message)

Array types

Both C and Pascal allow arrays 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;

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 of integer;

would be indexed by 0..9 (just as in C in this case). Array indices can be any ordinal data type, however, not just ranges:

type
   TColor = (red, green, blue);       (* enumeration *)
   RGB = array of 0..255;
var picture : array of RGB
var palette : array 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 declarations int a 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.

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. (Note : since 1986 and Turbo Pascal 3, which was the industry standard, GetMem() allows dynamic arrays in everyday Pascal, if not in the ISO standard)

C has the ability to initialize arrays of arbitrary length. The sizeof 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));
int i;
for (i=0; i<listSize; i++)
  puts(wordlist);
for (i=listSize-1; i>=0; i--)
  puts(wordlist);

Likewise modern Pascal, e.g. Delphi and Free Pascal, has a similar ability. Initialized arrays can be implemented as:

var
  wordlist: array of string = [
    'print', 'out', 'the', 'text', 'message'];
  i: Integer;
begin
  for i := Low(wordlist) to High(wordlist) do
    writeln(wordlist);
  for i := High(wordlist) downto Low(wordlist) do
    writeln(wordlist);
end.

Original 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 original 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  of char;
    length: wordrange
  end;
  wordlist = array of word;
var
  i: integer;
  words: wordlist;
procedure CreateList(var w: wordlist);
begin
  w.contents := 'print  ';
  w.length := 5;
  w.contents := 'out    ';
  w.length := 3;
  w.contents := 'the    ';
  w.length := 3;
  w.contents := 'text   ';
  w.length := 4;
  w.contents := 'message';
  w.length := 7;
end;
begin
  CreateList(words);
  for i := minlist to maxlist do
    with words do
      WriteLn(contents: length);
  for i := maxlist downto minlist do
    with words do
      WriteLn(contents: length)
end.

Strings

In both languages, a string is a primitive array of characters.

In Pascal a string literal of length n is compatible with the type packed array of char. In C a string generally has the type char.

Pascal has no support for variable-length arrays, and so any set of routines to perform string operations is dependent on a particular string size. 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 string literals are null-terminated; that is to say, 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 lacks built-in string or array assignment, so the string is not being transferred to p, but rather p is being made to point to the constant string in memory.

In Pascal, unlike C, the string's first character element is at index 1 and not 0 (leading it to be length-prefixed). This is because Pascal stores the length of the string at the 0th element of the character array. If this difference is not well understood it can lead to errors when porting or trying to interface object code generated by both languages.

FreeBSD developer Poul-Henning Kamp, writing in ACM Queue, would later refer to the victory of null-terminated strings over length-prefixed strings as "the most expensive one-byte mistake" ever.

Record types

Both C and Pascal can declare "record" types. In C, they are termed "structures".

struct a {
   int b;
   char c;
};
type a = record
   b: integer;
   c: char;
end;

In Pascal, we can use the sentence "with name_of_record do" in order to use directly the fields of that record, like local variables, instead of write name_of_record.name_of_field. Here there is an example:

type r = record
   s: string;
   c: char;
end;
var r1 : r;
begin
  with r1 do begin
    s := 'foo';
    c := 'b';
end;

There is no equivalent feature to with in C.

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 used depends on traits (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. In Pascal, such constructs are called variant records, not to be mistaken with the Variant datatype defined in Free Pascal.

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 tag field 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;
a = *(b+5);
a = *(5+b);
a = 5;

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 has the same kind of pointers as C, through the ^ referencing operator instead of the * of C. 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 of.

Expressions

This section does not cite any sources. Please help improve this section by adding citations to reliable sources. Unsourced material may be challenged and removed. (June 2013) (Learn how and when to remove this message)

Precedence levels

The languages differ significantly when it comes to expression evaluation, but all-in-all they are comparable.

Incomplete list of Pascal operators (e.g. shl, shr, xor, SizeOf, Inc, Dec are missing). This list needs to be completed.

Pascal

  1. Logical negation: not
  2. Multiplicative: * / div mod and
  3. Additive: + - or
  4. Relational: = <> < > <= >= in

C

  1. Unary postfix: () . -> ++ --
  2. Unary prefix: & * + - ! ~ ++ -- (type) sizeof
  3. Multiplicative: * / %
  4. Additive: + -
  5. Shift: << >>
  6. Relational: < > <= >=
  7. Equality: == !=
  8. Bitwise and: &
  9. Bitwise xor: ^
  10. Bitwise or: |
  11. Logical and: &&
  12. Logical or: ||
  13. Conditional: ? :
  14. Assignment: = += -= *= /= %= <<= >>= &= ^= |=
  15. 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 ALGOL, uses the mathematical equality operator = for the equality test and the symbol := for assignment, whereas C, like B, uses the mathematical equality operator for assignment. In C (and B) the == symbol of FORTRAN was chosen for the equality test.

It is a common mistake in C, due either to inexperience or to 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 which is non-zero and therefore considered "true" in C; this is in part because C (and ALGOL) allow multiple assignment in the form a = b = c = 10; which is not supported by Pascal. 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 and do not have a value: using the wrong operator will cause an unambiguous compilation error, and it's also less likely that anyone would mistake the := symbol for an equality test.

It is notable that ALGOL's conditional expression in the form z := if a > b then a else b; has an equivalent in C (the ternary operator from CPL) but not in Pascal, which will use if a > b then z:=a; else z:=b;.

Implementation issues

When Niklaus 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) / 3

are perfectly legal. And, in fact, they are, as far as the parser is concerned. Pascal does not 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 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.

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. (Note: since Turbo Pascal 3 (1986) the short-circuit Boolean evaluation is available in everyday Pascal, if not in the ISO standard).

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  of char;
  ...
  i := 1;
  while (i <= 10) and (a <> 'x') do i := i+1;
  ...

This seemingly straightforward search is problematic in Pascal because the array access a would be invalid for i equal to 11. There is more than one way to avoid this problem. The following example introduces a Boolean variable which indicates whether or not the target character has been found:

const
  strlen = 10;
var i: integer;
    a: packed array  of char;
    found: boolean;
  ...
  i := 1;
  found := false;
  while not found and (i <= strlen) do
    if (a = 'x') then found := true else i := i+1;
  ...

Alternatively, the test for end of array can be separated from the array access and a goto statement can break out of the search if the target is found:

label 99;
const
  strlen = 10;
var i: integer;
    a: packed array  of char;
  ...
  i := 1;
  repeat
    if a = 'x' then goto 99;
    i := i+1
    until i > strlen;
  99: 
  ...

Control structures

Statements for building control structures are roughly analogous and relatively similar (at least the first three).

PascalC
if cond then stmt else stmtif (cond) stmt else stmt
while cond do stmtwhile (cond) stmt
repeat stmt until conddo stmt while (cond);
for id := expr to expr do stmt
and
for id := expr downto expr do stmt
for (expr; cond; expr) stmt
case expr of
    expr : stmt;
    ...
    expr : stmt;
    else: stmt;
end
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 then default-case.

C has the so-called early-out statements break and continue, and some Pascals have them as well.

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 ability 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 and procedures

Pascal routines that return a value are called functions; routines that do not 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 void.

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). In both cases the variable name is used when calling (no need of address operator).

function f(z: integer; var k: integer): integer; // function accepts two integers, one by value, one by reference
Begin
  z:=1; // outer variable u will not be modified, but local value is modified in the function's scope
  k:=1; // outer variable t will be modified because it was passed by reference
  // up to here, z exists and equals 1
End;
x := f(u,t); // the variables u and t are passed to the call : the value of u and the reference to t

In C all parameters are passed by value but pass-by-reference can be simulated using pointers. The following segment is similar to the Pascal segment above:

int f(int z, int *k) { //function accepts an int (by value) and a pointer to int (also by value) as parameter
  z=1;  // idem Pascal, local value is modified but outer u will not be modified
  *k=1; // variable referenced by k (eg, t) will be modified
  // up to here, z exists and equals 1
}
x = f(u,&t); // the value of u and the (value of) address of variable t are passed to the call

One of the most important difference between C and Pascal is the way they handle the parameters on stack during a subroutine call : This is called the calling convention : PASCAL-style parameters are pushed on the stack in left-to-right order. The STDCALL calling convention of C pushes the parameters on the stack in right-to-left order.

Pascal-style procedure call is made with :

  • caller pushing parameters into the stack in left-to-right order (opposite of __cdecl)
  • calling the function
  • stack is cleaned up by the callee
    ; example of pascal-style call.
    ; NOTE: __stdcall would push the arguments in reverse order.
    push arg1
    push arg2
    push arg3
    call function
    ; no stack cleanup upon return: callee did it

The advantage of PASCAL call over STDCALL is that the code is slightly smaller, though the size impact is only visible in large programs, and that recursion works faster.

Variadic functions are almost impossible to get right with PASCAL and STDCALL methods, because only the caller really knows how many arguments were passed in order to clean them up.

C allows for functions to accept a variable number of parameters, known as variadic functions, using a clumsy mechanism of va_list ap;, va_start(ap, count);, va_arg(ap, type); with limited type availability (example : nothing for bool)

int f(int a, ...);
f(1, 2, 3, 4, 5);

The function f() uses a special set of functions (varargs) that allow it to access each of the parameters in turn.

Pascal and C also have some variadic I/O functions, for instance WriteLn() and printf().

Modern Pascals enable a variable number of parameters for functions :

procedure writeLines(const arguments: array of const); // parsed via : for argument in arguments do

They also enable to interface with varargs C functions :

Function PrintF1(fmt : pchar); cdecl; varargs;  external 'c' name 'printf';

Pascal allows procedures and functions to be nested. This is convenient to allow variables that are local to a group of procedures, but not global. C lacks this feature and the localization of variables or functions can be done only for a compiling module wherein the variables or functions would have been declared static.

C and Pascal allow 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 <string.h>
int (*cmpar)(const char *a, const char *b);
const char *s1 = "hello";
const char *s2 = "world";
cmpar = &strcmp;
b = (*cmpar)(s1, s2);

In Pascal functions and procedures can 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 "preprocessor"; a separate program, and pass, that handled constant, include and macro definitions, 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, leading to the syntax we see today.

Pascal constant and type defines are built in and don't need a preprocessor. 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 does not 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

In C, the programmer may inspect the byte-level representation of any object by pointing a char pointer to it:

int a;
char *p = (char *)(&a);
char c = *p;  // first byte of a

It may be possible to do something similar 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 most Pascal compilers and interpreters, even in the code above a2c.a and a2c.b are not 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, Java 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 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.

See also

Notes

  1. Kamp, Poul-Henning (25 July 2011), "The Most Expensive One-byte Mistake", ACM Queue, 9 (7): 40–43, doi:10.1145/2001562.2010365, ISSN 1542-7730, S2CID 30282393
  2. "Typecast - Lazarus wiki". wiki.freepascal.org. Retrieved 2024-05-18.

Further reading

Pascal programming language family
Dialects
Compilers
Current
Discontinued
API
Microcomputer
Comparisons
Designer
Related to
ALGOL (1958)
Modula-2 (1977)
Ada (1983)
Oberon (1986)
Modula-3 (1988)
Oberon-2 (1991)
Component Pascal (1991)
C programming language
Features
Standard library
Implementations
Compilers
IDEs
Comparison with
other languages
Descendant
languages
Designer
Categories:
Comparison of Pascal and C: Difference between revisions Add topic