A Comparison of the Syntax of C and Pascal - ---------- -- --- ------ -- - --- ------ *** FIELD-TEST VERSION 1.2 *** copyright (c) 1993, 1992, 1989 Russell C. Bjork Professor of Computer Science Gordon College, Wenham, MA PRELIMINARY NOTE: ---------------- Two major dialects of C are currently supported by various systems: "traditional C" (supported by the C compiler distributed with most Unix systems) and ANSI C (an improved dialect standardized by ANSI.) This document will describe features of both dialects. Note that traditional C is the dialect supported by standard Unix systems. An ANSI C compiler will accept programs written in traditional C (but not vice versa), so traditional C must be used in many cases; however, where available, ANSI C is much improved in regard to its handling of the type checking of arguments to functions. Page 1 Pascal C ------ - Lexical Conventions ------- ----------- Not case-sensitive; upper and lower Case-sensitive; upper and lower case case letters are equivalent - so letters are different - so somename, SOMENAME, Somename, SomeName somename, SOMENAME, Somename, SomeName etc. are all the same. are all different -------------------------------------------------------------------------------- Comments -------- (* This is a comment *) /* This is a comment */ -------------------------------------------------------------------------------- Constants --------- The rules for numeric constants (integer, real) are essentially the same, though C is a bit more flexible. (See a C reference manual for details.) 'c' 'c' 'This is a string' "This is a string" NOTES: 1. Non-printing characters may be embedded in either character or string constants by using various escapes - e.g. \0 - null character \n - newline \t - tab \b - backspace \f - formfeed \\ - \ \' - ' \" - " \ddd - Character whose OCTAL code is ddd - e.g. '\101' is the same as 'A'. 2. String constants are terminated by a null character \0. Thus, the total space allocated for a string is one more than the number of characters in it. Page 2 3. String constants may be continued over more than one line by having a \ be the very last character on the line to be continued - e.g. "This is a string constant that ex\ tends over more than one line." -------------------------------------------------------------------------------- const #define size 100 size = 100; #define pi 3.14159 pi = 3.14159; #define first 'A' first = 'A'; #define filename "XYZ.DAT" filename = 'XYZ.DAT'; -------------------------------------------------------------------------------- Declarations of variables ------------ -- --------- var int i; i: integer; float r; r: real; int b; b: boolean; char c; c: char; int j, k, l; j, k, l: integer; NOTES: 1. C does not use a word like var to introduce variable declarations - it just declares them. 2. C does not have a separate type for boolean values. Int is used, with 1 = true and 0 = false. 3. In addition to the scalar types shown above, C has: short int (may be abbreviated short) long int (may be abbreviated long) double 4. Any integer type (including char) may be prefixed by unsigned - e.g. unsigned int i; unsigned char c; -------------------------------------------------------------------------------- Page 3 var int a[10]; a: array[0..9] of integer; float b[5][10]; b: array[0..4, 0..9] of real; NOTE: Arrays in C always have subscripts ranging from 0 to declared size - 1. c: array[1..10] of char; NO DIRECT EQUIVALENT IN C. WORK AROUND THIS BY DECLARING: char c[10]; AND LETTING SUBSCRIPTS RANGE FROM 0..9. NOTE: C does not distinguish between packed and unpacked arrays -------------------------------------------------------------------------------- var struct student: record { int id; id: integer; char name[10]; name: packed array[1..10] float gpa; of char; } student; gpa: real end; -------------------------------------------------------------------------------- For this example, suppose the types employee and student have been previously declared: var union borrower: record { employee EBorr; case boolean of student SBorr; false: (EBorr: employee); } borrower; true: (SBorr: student) end; NOTES: 1. There is no provision for an explicit tag field in C unions, analogous to the tag field of a Pascal variant record. var NO DIRECT EQUIVALENT IN C. borrower: record case IsStudent: boolean of false: (EBorr: employee); true: (SBorr: student) end; Page 4 2. There is no provision for a record structure with both a fixed and a variant part, as in Pascal. var NO DIRECT EQUIVALENT IN C. borrower: record id: integer; name: packed array[1..10] of char; case boolean of false: (EBorr: employee); true: (SBorr: student) end; -------------------------------------------------------------------------------- var enum {chocolate, vanilla} flavor; flavor: (chocolate, vanilla); NOTE: As in Pascal, it is usually better style with record and enumeration types (and often with array types) to first declare a named type and then a variable of that type. See below. -------------------------------------------------------------------------------- var squares: set of 1..9; NO DIRECT EQUIVALENT IN C. SOMEWHAT OF THE SAME EFFECT CAN SOMETIMES BE BE OBTAINED BY 1. Treating a longword as a bit vector representing of basetype size up to 32. Bitwise operations can be used to get the effect of set operations, e.g. int squares; ... squares := []; squares = 0; ... ... squares := squares + [2] squares = squares | 1 << 2; 2. Some C library routines allow a character string to be used like a set of char - but not as efficiently, e.g. const vowels = ['A','a','E','e', #define VOWELS "AaEeIiOoUu" 'I','i','O','o','U','u']; ... ... if c in vowels then if (index(VOWELS, c)) ... ... -------------------------------------------------------------------------------- Page 5 NO PASCAL EQUIVALENT The type specifier for a variable may optionally be preceeded by one of the following storage class specifiers: auto, extern, register, static e.g. auto int i; extern int r; register int i; static int i; (Extern is the default for functions and top-level variables; auto is the default for local variables declared in functions.) -------------------------------------------------------------------------------- NO STANDARD PASCAL EQUIVALENT (BUT A C variable may be initialized when MANY DIALECTS ALLOW THIS) it is declared - e.g. int i = 3; char c = 'A'; float a[3] = { 1.0, 2.0, 3.0 }; struct { char name[10]; float gpa; } student = { "AARDVARK", 4.0 }; -------------------------------------------------------------------------------- Declarations of new types ------------ -- --- ----- type typedef float realarray[10]; realarray = array[0..9] of real; realarray a; var a: realarray; -------------------------------------------------------------------------------- Page 6 type typedef struct student = record { int id; id: integer; char name[10]; name: packed array[1..10] float gpa; of char; } student; gpa: real end; student someone; var someone: student; struct student { int id; char name[10]; float gpa; }; struct student someone; -------------------------------------------------------------------------------- For this example, suppose the types employee and student have been previously declared: type typedef union borrower = record { employee EBorr; case boolean of student SBorr; false: (EBorr: employee); } borrower; true: (SBorr: student) end; borrower someone; var someone: borrower; union borrower { employee EBorr; student SBorr; }; union borrower someone; -------------------------------------------------------------------------------- type typedef flavortype = (chocolate, vanilla); enum {chocolate, vanilla} flavortype; var flavortype flavor; flavor: flavortype; enum flavortype {chocolate, vanilla}; enum flavortype flavor; -------------------------------------------------------------------------------- Page 7 Pointers -------- var int *p; p: ^integer; first: ^student; student *first; struct student *first; (depending on whether student was declared using typedef or not) -------------------------------------------------------------------------------- type typedef stuptr = ^node; student *stuptr; var first: stuptr; stuptr first; typedef struct student *stuptr; stuptr first; (Depending on how student was declared) -------------------------------------------------------------------------------- type typedef nodeptr = ^node; struct node node = record { info: integer; int info; link: nodeptr struct node *link; end; } node, *nodeptr; var nodeptr first; first: nodeptr; typedef struct node * nodeptr; typedef struct node { int info; nodeptr link; } node; nodeptr first; -------------------------------------------------------------------------------- (Given the above declarations) new(first) first = (nodeptr) malloc(sizeof(node)); -------------------------------------------------------------------------------- Page 8 NO PASCAL EQUIVALENT In C, the type array is equivalent to a pointer type to the element type of the array. Thus, the following pairs of operations are equivalent; either syntax can be used regardless of whether a is declared as an array or a pointer: a[0] = 1; IS EQUIVALENT TO *a = 1; a[3] = 1; IS EQUIVALENT TO *(a+3)= 1; Note that arithmetic on pointers is done in units of the size of the basetype. Thus, if ints occupy 4 bytes, then *(a+3) actually adds 12 to to calculate the desired address. Also, for formal parameters only, int a[]; IS EQUIVALENT TO int *a; As a consequence of this, the following code segments are NOT equivalent var a, b: array[0..9] of real; float a[10], b[10]; ... ... b := a; <- NOT AT ALL THE SAME -> b = a; (In fact, this would not even be syntactically legal unless b were a formal parameter of a procedure.) C allows assignment of entire structures, but NOT arrays. The equivalent C code for the Pascal array assignment is for (i=0; i < 10; i++) b[i] = a[i]; -------------------------------------------------------------------------------- Functions and Procedures --------- --- ---------- function f(x, y: integer; z: real): real; float f(x, y, z) int x, y; float z; var { q: integer; int q; begin q = x*x + y; q := sqr(x) + y; return q - z; f := q - z } end; Page 9 float f(int x, int y, float z) { int q; q = x*x + y; return q - z; } NOTE WELL THE DIFFERENCES IN USAGE OF SEMICOLONS BETWEEN PASCAL AND C -------------------------------------------------------------------------------- procedure p(x: integer); void p(x) int x; var { temp: integer; int temp; begin ... ... return; end; } void p(int x) { int temp; ... return; } NOTE: In either dialect, the return statement is optional at the end of the code. A return statement or statements may also appear in the middle of the code. -------------------------------------------------------------------------------- Given: Given: function f: integer; int f() ... ... procedure p; void p() ... ... These routines are called by: These routines are called by: x := f; x = f(); p; p(); Page 10 -------------------------------------------------------------------------------- procedure p(var x: integer); void p(x) int *x; begin { x := 17 *x = 17; end; } void p(int *x) { *x = 17; } This routine is called by: In either dialect, this routine is called by: p(i); p(&i); (where i is an integer variable) (where i is an int variable) -------------------------------------------------------------------------------- type realarray = array[0..9] of real; procedure p(var a: realarray); void p(a) float a[]; begin { a[1] := a[2] + a[3] a[1] = a[2] + a[3]; end; } OR, BECAUSE OF THE EQUIVALENCE OF ARRAYS AND POINTERS: void p(a) float *a; { a[1] = a[2] + a[3]; } void p(float a[]) { a[1] = a[2] + a[3]; } void p(float *a) { a[1] = a[2] + a[3]; } Page 11 -------------------------------------------------------------------------------- function f(c: char): integer; forward; int f(); int f(char c); int f(char); -------------------------------------------------------------------------------- function f(c: char): integer; external; int f(); int f(char c); int f(char); -------------------------------------------------------------------------------- program .... main() { ... ... } begin (* main program *) ... main(argc, argv) end. int argc; char *argv[]; { ... } main(int argc, char * argv[]) { ... } -------------------------------------------------------------------------------- Page 12 Operators and Expressions --------- --- ----------- C operators are grouped in decreasing order of precedence. All operators in the same group have the same precedence. L and R indicate left and right associativity, respectively. The names used in examples stand for variables or expressions of a certain type, as follows: x, y - no particular type i, j - integers b, c - boolean p - pointer s - struct t - type name s.name s.name p^.name p -> name NO PASCAL EQUIVALENT (post-increment) x++ NO PASCAL EQUIVALENT (post-decrement) x-- NO PASCAL EQUIVALENT (pre-increment) ++x NO PASCAL EQUIVALENT (pre-decrement) --x p^ *p NO PASCAL EQUIVALENT (address of) &x +x NO C EQUIVALENT -x -x not x !x NO PASCAL EQUIVALENT (bitwise not) ~i NO PASCAL EQUIVALENT (type cast) (t) x NO PASCAL EQUIVALENT (size in bytes) sizeof x NO PASCAL EQUIVALENT (size in bytes) sizeof (t) x * y x * y L x / y x / y L i div j i / j L i mod j i % j L x + y x + y L x - y x - y L NO PASCAL EQUIVALENT (left shift) i << j L NO PASCAL EQUIVALENT (right shift) i >> j L x < y x < y L x > y x > y L x <= y x <= y L x >= y x >= y L x = y x == y L x <> y x != y L Page 13 NO PASCAL EQUIVALENT (bitwise and) i & j L NO PASCAL EQUIVALENT (bitwise xor) i ^ j L NO PASCAL EQUIVALENT (bitwise or) i | j L b and c b && c L b or c b || c L NO PASCAL EQUIVALENT (conditional expr) b ? x : y R x := y x = y R x := x + y x += y R x := x - y x -= y R x := x * y x *= y R i := i div j i /= j R x := x / y x /= y R i := i mod j i %= j R NO PASCAL EQUIVALENT (see above) i <<= j R NO PASCAL EQUIVALENT " " i >>= j R NO PASCAL EQUIVALENT " " i &= j R NO PASCAL EQUIVALENT " " i ^= j R NO PASCAL EQUIVALENT " " i |= j R NO PASCAL EQUIVALENT (sequential eval) x, y L -------------------------------------------------------------------------------- Page 14 Executable Statements ---------- ---------- x := y + z x = y + z; NOTE: This is an instance of the C expression statement, which is actually much more flexible than its Pascal equivalent. The following is also legal (but contorted!) if (w += x = y++ * z) u = ++w; This is equivalent to: x = y * z; y = y + 1; w = w + x; if (w != 0) { w = w + 1; u = w; } -------------------------------------------------------------------------------- begin { x := y + z; x = y + z; w := x w = x; end } NOTES: 1. There is never a semicolon after the terminating } , but the last statement inside the compound statement does end with a semicolon. 2. The C compound statement may begin with declarations for local variables - e.g. NO PASCAL EQUIVALENT { int temp; temp = y; y = z; z = temp; } -------------------------------------------------------------------------------- Page 15 if x < 0 then if (x < 0) x := -x x = -x; if x > y then if (x > y) max := x max = x; else else max := y max = y; NOTE: In C, a semicolon is a statement terminator, not a statement separator - so it MUST be used before else in a case like this. -------------------------------------------------------------------------------- while x < y do while (x < y) x := 2 * x x = 2 * x; -------------------------------------------------------------------------------- repeat do x := 2 * x; { y := y - 1 x = 2 * x; until x >= y y--; } while (x < y); NOTE: The sense of the condition is the opposite from Pascal. C is consistent about always requiring compound statements to be surrounded by braces. -------------------------------------------------------------------------------- for i := 1 to n do for (i = 1 ; i <= n ; i++) x[i] := 0 x[i] = 0; NOTE: The C for is considerably more flexible than the Pascal for. NO PASCAL EQUIVALENT USING FOR for (i = 1; i <= n; i += 10) x[i] = 0; (Zeroes x[1], x[11], x[21] .. ) NO PASCAL EQUIVALENT USING FOR for (i = 1; i <= n && x[i] != 0; i++); (Finds first element of x[] that is 0; stops if all n elements are examined without finding one.) -------------------------------------------------------------------------------- Page 16 case i of switch (i) { 1: write('one'); case 1: printf("one"); 2: write('two'); break; 3: write('three'); case 2: printf("two"); 4: begin break; write('four'); case 3: printf("three"); i := 3 break; end case 4: printf("four"); i = 3; otherwise break; write('Bad value') default: printf("Bad value"); } end; NOTE: If the breaks are omitted, control flows through case to case. Thus, the following are equivalent: case i of switch(i) { 0: write('ZeroOne'); case 0: printf("Zero"); 1: write('One') case 1: printf("One"); } end; -------------------------------------------------------------------------------- if, while, repeat, for, or case if, while, do, for, or switch begin { ... ... ... ... goto 1 break; ... ... end; } 1: while, repeat, or for while, do, or for begin { ... ... ... ... goto 1; continue; ... ... 1: } end -------------------------------------------------------------------------------- Page 17 procedure p ... void p( ... ... ... goto 1; return; ... ... 1: end function f ... int f( ... ... ... f := somevalue; return (somevalue); goto 1; ... ... 1: end -------------------------------------------------------------------------------- goto 1; goto fini; ... ... 1: ... fini: ... -------------------------------------------------------------------------------- ; -- the null statement ; -- the null statement -------------------------------------------------------------------------------- Page 18 The C Pre-processor --- - ------------- The C Compiler includes a pre-processor, that performs certain modifications on the program text BEFORE the compiler proper sees it. The following are examples of pre-processor directives found in typical C implementations, though some do not have all of these and some may have more. Note the similarity between the macro facility typically found in assemblers and the C pre-processor's #define and #if/#ifdef directives. const size = 10 #define size 10 NO PASCAL EQUIVALENT #define iszero(e) (e == 0) NO PASCAL EQUIVALENT #define equal(x, y) (x == y) NO PASCAL EQUIVALENT #define error(f, m) if (f) \ printf(m) NO PASCAL EQUIVALENT #define VAX NO PASCAL EQUIVALENT #undef VAX NO PASCAL EQUIVALENT #if wordlength >= 32 typedef int myint; #else typedef long myint; #endif NO PASCAL EQUIVALENT #ifdef VAX ... VAX-specific code #endif NO PASCAL EQUIVALENT #ifndef size #define size 100 /* default */ #endif -------------------------------------------------------------------------------- C makes extensive use of header files incorporating declarations for constants, data, and code to support splitting a program across multiple source files. The #include directive is used to incorporate the contents of a header file into a source program. NO PASCAL EQUIVALENT #include NO PASCAL EQUIVALENT #include "myinclude.c" NOTE: The form is used for standard header files defining C library routines, which reside in a system directory; the "filename" form is used for programmer-written header files normally residing in the same directory as the program being compiled.