Pascal Variable Assignment In C

For assignment of letters to disk file systems, see Drive letter assignment.

In computer programming, an assignment statement sets and/or re-sets the value stored in the storage location(s) denoted by a variablename; in other words, it copies a value into the variable. In most imperativeprogramming languages, the assignment statement (or expression) is a fundamental construct.

Today, the most commonly used notation for this basic operation has come to be (originally Superplan 1949–51, popularized by Fortran 1957 and C) followed by [1] (originally ALGOL 1958, popularised by Pascal),[2] although there are many other notations in use. In some languages the symbol used is regarded as an operator (meaning that the assignment has a value) while others define the assignment as a statement (meaning that it cannot be used in an expression).

Assignments typically allow a variable to hold different values at different times during its life-span and scope. However, some languages (primarily strictly functional) do not allow that kind of "destructive" reassignment, as it might imply changes of non-local state. The purpose is to enforce referential transparency, i.e. functions that do not depend on the state of some variable(s), but produce the same results for a given set of parametric inputs at any point in time. Modern programs in other languages also often use similar strategies, although less strict, and only in certain parts, in order to reduce complexity, normally in conjunction with complementing methodologies such as data structuring, structured programming and object orientation.

Semantics[edit]

An assignment operation is a process in imperative programming in which different values are associated with a particular variable name as time passes.[1] The program, in such model, operates by changing its state using successive assignment statements.[2][3] Primitives of imperative programming languages rely on assignment to do iteration.[4] At the lowest level, assignment is implemented using machine operations such as or .[2][4]

Variables are containers for values. It is possible to put a value into a variable and later replace it with a new one. An assignment operation modifies the current state of the executing program.[3] Consequently, assignment is dependent on the concept of variables. In an assignment:

  • The is evaluated in the current state of the program.
  • The is assigned the computed value, replacing the prior value of that variable.

Example: Assuming that is a numeric variable, the assignment means that the content of the variable is doubled after the execution of the statement.

An example segment of C code:

intx=10;floaty;x=23;y=32.4f;

In this sample, the variable is first declared as an int, and is then assigned the value of 10. Notice that the declaration and assignment occur in the same statement. In the second line, is declared without an assignment. In the third line, is reassigned the value of 23. Finally, is assigned the value of 32.4.

For an assignment operation, it is necessary that the value of the is well-defined (it is a valid rvalue) and that the represents a modifiable entity (it is a valid modifiable (non-const) lvalue). In some languages, typically dynamic ones, it is not necessary to declare a variable prior to assigning it a value.

Single assignment[edit]

See also: Static single assignment form

Any assignment that changes an existing value (e.g. ) is disallowed in purely functional languages.[4] In functional programming, assignment is discouraged in favor of single assignment, also called initialization. Single assignment is an example of name binding and differs from assignment as described in this article in that it can only be done once, usually when the variable is created; no subsequent reassignment is allowed.

An evaluation of expression does not have a side effect if it does not change an observable state of the machine,[5] and produces same values for same input.[4] Imperative assignment can introduce side effects while destroying and making the old value unavailable while substituting it with a new one,[6] and is referred to as destructive assignment for that reason in LISP and functional programming, similar to destructive updating.

Single assignment is the only form of assignment available in purely functional languages, such as Haskell, which do not have variables in the sense of imperative programming languages[4] but rather named constant values possibly of compound nature with their elements progressively defined on-demand. Purely functional languages can provide an opportunity for computation to be performed in parallel, avoiding the von Neumann bottleneck of sequential one step at time execution, since values are independent of each other.[7]

Impure functional languages provide both single assignment as well as true assignment (though true assignment is typically used with less frequency than in imperative programming languages). For example, in Scheme, both single assignment (with ) and true assignment (with ) can be used on all variables, and specialized primitives are provided for destructive update inside lists, vectors, strings, etc. In OCaml, only single assignment is allowed for variables, via the syntax; however destructive update can be used on elements of arrays and strings with separate operator, as well as on fields of records and objects that have been explicitly declared mutable (meaning capable of being changed after their initial declaration) by the programmer.

Functional programming languages that use single assignment include Clojure (for data structures, not vars), Erlang (it accepts multiple assignment if the values are equal, in contrast to Haskell), F#, Haskell, Lava, OCaml, Oz (for dataflow variables, not cells), Racket (for some data structures like lists, not symbols), SASL, Scala (for vals), SISAL, Standard ML. Non-backtrackingProlog code can be considered explicit single-assignment, explicit in a sense that its (named) variables can be in explicitly unassigned state, or be set exactly once. In Haskell, by contrast, there can be no unassigned variables, and every variable can be thought of as being implicitly set to its value (or rather to a computational object that will produce its value on demand) when it is created.

Value of an assignment[edit]

In some programming languages, an assignment statement returns a value, while in others it does not.

In most expression-oriented programming languages (for example, C), the assignment statement returns the assigned value, allowing such idioms as , in which the assignment statement returns the value of , which is then assigned to . In a statement such as , the return value of a function is used to control a loop while assigning that same value to a variable.

In other programming languages, Scheme for example, the return value of an assignment is undefined and such idioms are invalid.

In Haskell,[8] there is no variable assignment; but operations similar to assignment (like assigning to a field of an array or a field of a mutable data structure) usually evaluate to the unit type, which is represented as . This type has only one possible value, therefore containing no information. It is typically the type of an expression that is evaluated purely for its side effects.

Variant forms of assignment[edit]

Certain use patterns are very common, and thus often have special syntax to support them. These are primarily syntactic sugar to reduce redundancy in the source code, but can also simplify compilation by clarifying the programmer's intent and easing analysis of the source code.

Augmented assignment[edit]

Main article: Augmented assignment

The case where the assigned value depends on a previous one is so common that many imperative languages, most notably C and the majority of its descendants, provide special operators called augmented assignment, like , so can instead be written as .[3] Beyond syntactic sugar, this simplifies compilation, since it makes it clear that in-place modification of the variable is possible.

Chained assignment[edit]

A statement like is called a chained assignment in which the value of is assigned to multiple variables and . Chained assignments are often used to initialize multiple variables, as in

Not all programming languages support chained assignment. Chained assignments are equivalent to a sequence of assignments, but the evaluation strategy differs between languages. For simple chained assignments, like initializing multiple variables, the evaluation strategy does not matter, but if the targets (l-values) in the assignment are connected in some way, the evaluation strategy affects the result.

In some programming languages (C for example), chained assignments are supported because assignments are expressions, and have values. In this case chain assignment can be implemented by having a right-associative assignment, and assignments happen right-to-left. For example, is equivalent to . In C++ they are also available for values of class types by declaring the appropriate return type for the assignment operator.

In Python, assignment statements are not expressions and thus do not have a value. Instead, chained assignments are a series of statements with multiple targets for a single expression. The assignments are executed left-to-right so that evaluates the expression , then assigns the result to the leftmost target, , and then assigns the same result to the next target, , using the new value of .[9] This is essentially equivalent to though no actual variable is produced for the temporary value.

Parallel assignment[edit]

Some programming languages, such as APL, Go,[10]JavaScript (since 1.7), PHP, Maple, Lua, occam 2,[11]Perl,[12]Python,[13]REBOL, Ruby,[14] and Windows PowerShell allow several variables to be assigned in parallel, with syntax like:

a, b := 0, 1

which simultaneously assigns 0 to and 1 to . This is most often known as parallel assignment; it was introduced in CPL in 1963, under the name simultaneous assignment,[15] and is sometimes called multiple assignment, though this is confusing when used with "single assignment", as these are not opposites. If the right-hand side of the assignment is a single variable (e.g. an array or structure), the feature is called unpacking[16] or destructuring assignment:[17]

var list := {0, 1} a, b := list

The list will be unpacked so that 0 is assigned to and 1 to . More interestingly,

a, b := b, a

swaps the values of and . In languages without parallel assignment, this would have to be written to use a temporary variable

var t := a a := b b := t

since leaves both and with the original value of .

Some languages, such as Go and Python, combine parallel assignment, tuples, and automatic tuple unpacking to allow multiple return values from a single function, as in this Python example:

deff():return1,2a,b=f()

This provides an alternative to the use of output parameters for returning multiple values from a function. This dates to CLU (1974), and CLU helped popularize parallel assignment generally.

In C and C++, the comma operator is similar to parallel assignment in allowing multiple assignments to occur within a single statement, writing instead of . This is primarily used in for loops, and is replaced by parallel assignment in other languages such as Go.[18] However, the above C++ code does not ensure perfect simultaneity, since the right side of the following code is evaluated after the left side. In languages such as Python, will assign the two variables concurrently, using the initial value of a to compute the new b.

Assignment versus equality[edit]

See also: Relational operator § Confusion with assignment operators

The use of the equals sign as an assignment operator has been frequently criticized, due to the conflict with equals as comparison for equality. This results both in confusion by novices in writing code, and confusion even by experienced programmers in reading code. The use of equals for assignment dates back to Heinz Rutishauser's language Superplan, designed from 1949 to 1951, and was particularly popularized by Fortran:

A notorious example for a bad idea was the choice of the equal sign to denote assignment. It goes back to Fortran in 1957[a] and has blindly been copied by armies of language designers. Why is it a bad idea? Because it overthrows a century old tradition to let “=” denote a comparison for equality, a predicate which is either true or false. But Fortran made it to mean assignment, the enforcing of equality. In this case, the operands are on unequal footing: The left operand (a variable) is to be made equal to the right operand (an expression). x = y does not mean the same thing as y = x.[19]

— Niklaus Wirth, Good Ideas, Through the Looking Glass

Beginning programmers sometimes confuse assignment with the relational operator for equality, as "=" means equality in mathematics, and is used for assignment in many languages. But assignment alters the value of a variable, while equality testing tests whether two expressions have the same value.

In some languages, such as BASIC, a single equals sign () is used for both the assignment operator and the equality relational operator, with context determining which is meant. Other languages use different symbols for the two operators. For example:

  • In Pascal, the assignment operator is a colon and an equals sign () while the equality operator is a single equals ().
  • In C, the assignment operator is a single equals sign () while the equality operator is a pair of equals signs ().
  • In R, the assignment operator is basically , as in , but a single equals sign can be used in certain contexts.

The similarity in the two symbols can lead to errors if the programmer forgets which form ("", "", "") is appropriate, or mistypes "" when "" was intended. This is a common programming problem with languages such as C (including one famous attempt to backdoor the Linux kernel [20]), where the assignment operator also returns the value assigned (in the same way that a function returns a value), and can be validly nested inside expressions. If the intention was to compare two values in an statement, for instance, an assignment is quite likely to return a value interpretable as Boolean true, in which case the clause will be executed, leading the program to behave unexpectedly. Some language processors (such as gcc) can detect such situations, and warn the programmer of the potential error.

Notation[edit]

See also: Comparison of programming languages (variable and constant declarations)

The two most common representations for the copying assignment are equals sign () and colon-equals (). Both forms may semantically denote either an assignment statement or an assignment operator (which also has a value), depending on language and/or usage.

Fortran, PL/I, C (and descendants such as C++, Java, etc.), Bourne shell, Python, Go (assignment to pre-declared variables), R, Windows PowerShell, etc.
ALGOL (and derivatives), Simula, CPL, BCPL, Pascal[21] (and descendants such as Modula), Mary, PL/M, Ada, Smalltalk, Eiffel,[22][23]Oberon, Dylan,[24]Seed7, Go (shorthand for declaring and defining a variable),[25]Io, AMPL, ML,[26] etc.

Other possibilities include a left arrow or a keyword, though there are other, rarer, variants:

Mathematical pseudo code assignments are generally depicted with a left-arrow.

Some platforms put the expression on the left and the variable on the right:

Some expression-oriented languages, such as Lisp[28][29] and Tcl, uniformly use prefix (or postfix) syntax for all statements, including assignment.

See also[edit]

Notes[edit]

References[edit]

  1. ^ abTopics in Information Processing
  2. ^ abcImperative Programming
  3. ^ abcRuediger-Marcus Flaig (2008). Bioinformatics programming in Python: a practical course for beginners. Wiley-VCH. pp. 98–99. ISBN 978-3-527-32094-3. Retrieved 25 December 2010. 
  4. ^ abcdeCrossing borders: Explore functional programming with HaskellArchived November 19, 2010, at the Wayback Machine., by Bruce Tate
  5. ^Mitchell, John C. (2003). Concepts in programming languages. Cambridge University Press. p. 23. ISBN 978-0-521-78098-8. Retrieved 3 January 2011. 
  6. ^Imperative Programming Languages (IPL)
  7. ^John C. Mitchell (2003). Concepts in programming languages. Cambridge University Press. pp. 81–82. ISBN 978-0-521-78098-8. Retrieved 3 January 2011. 
  8. ^Hudak, Paul (2000). The Haskell School of Expression: Learning Functional Programming Through Multimedia. Cambridge: Cambridge University Press. ISBN 0-521-64408-9. 
  9. ^https://docs.python.org/reference/simple_stmts.html#assignment-statements
  10. ^The Go Programming Language Specification: Assignments
  11. ^INMOS Limited, ed. (1988). Occam 2 Reference Manual. New Jersey: Prentice Hall. ISBN 0-13-629312-3. 
  12. ^Wall, Larry; Christiansen, Tom; Schwartz, Randal C. (1996). Perl Programming Language (2 ed.). Cambridge: O´Reilly. ISBN 1-56592-149-6. 
  13. ^Lutz, Mark (2001). Python Programming Language (2 ed.). Sebastopol: O´Reilly. ISBN 0-596-00085-5. 
  14. ^Thomas, David; Hunt, Andrew (2001). Programming Ruby: The Pragmatic Programmer's Guide. Upper Saddle River: Addison Wesley. ISBN 0-201-71089-7. 
  15. ^D.W. Barron et al., "The main features of CPL", Computer Journal6:2:140 (1963). full text (subscription)
  16. ^http://legacy.python.org/dev/peps/pep-3132/
  17. ^https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Destructuring_assignment
  18. ^Effective Go: for, "Finally, Go has no comma operator and ++ and -- are statements not expressions. Thus if you want to run multiple variables in a for you should use parallel assignment (although that precludes ++ and --)."
  19. ^Niklaus Wirth. "Good Ideas, Through the Looking Glass". CiteSeerX 10.1.1.88.8309. 
  20. ^Corbet (6 November 2003). "An attempt to backdoor the kernel". 
  21. ^Moore, Lawrie (1980). Foundations of Programming with Pascal. New York: John Wiley & Sons. ISBN 0-470-26939-1. 
  22. ^Meyer, Bertrand (1992). Eiffel the Language. Hemel Hempstead: Prentice Hall International(UK). ISBN 0-13-247925-7. 
  23. ^Wiener, Richard (1996). An Object-Oriented Introduction to Computer Science Using Eiffel. Upper Saddle River, New Jersey: Prentice Hall. ISBN 0-13-183872-5. 
  24. ^Feinberg, Neal; Keene, Sonya E.; Mathews, Robert O.; Withington, P. Tucker (1997). Dylan Programming. Massachusetts: Addison Wesley. ISBN 0-201-47976-1. 
  25. ^The Go Programming Language Specification: short variable declarations
  26. ^Ullman, Jeffrey D. (1998). Elements of ML Programming: ML97 Edition. Englewood Cliffs, New Jersey: Prentice Hall. ISBN 0-13-790387-1. 
  27. ^Iverson, Kenneth E. (1962). A Programming Language. John Wiley and Sons. ISBN 0-471-43014-5. 
  28. ^Graham, Paul (1996). ANSI Common Lisp. New Jersey: Prentice Hall. ISBN 0-13-370875-6. 
  29. ^Steele, Guy L. (1990). Common Lisp: The Language. Lexington: Digital Press. ISBN 1-55558-041-6. 
  30. ^Dybvig, R. Kent (1996). The Scheme Programming Language: ANSI Scheme. New Jersey: Prentice Hall. ISBN 0-13-454646-6. 
  31. ^Smith, Jerry D. (1988). Introduction to Scheme. New Jersey: Prentice Hall. ISBN 0-13-496712-7. 
  32. ^Abelson, Harold; Sussman, Gerald Jay; Sussman, Julie (1996). Structure and Interpretation of Computer Programs. New Jersey: McGraw-Hill. ISBN 0-07-000484-6. 
  1. ^Use of predates Fortran, though it was popularized by Fortran.

The computer programming languagesC 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 and ) and also Pascal (for example in case of enumerations, , and booleans). Some Pascal dialects also incorporated traits from C.

What is documented here is the Pascal of Niklaus Wirth, as standardized as ISO 7185 in 1982. The C documented is the language of Brian 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[edit]

Syntactically, Pascal is much more ALGOL-like than C. English keywords are retained where C uses punctuation symbols – Pascal has , , and where C uses , , and for example. However, C is actually more ALGOL-like than Pascal regarding (simple) declarations, retaining the type-namevariable-name syntax. For example, C can accept declarations at the start of any block, not just the outer block of a function.

Semicolon use[edit]

Another, more subtle, difference is the role of the semicolon. In Pascal semicolons separate individual statements within a compound statement whereas they terminate the statement in C. They are also syntactically part of the statement itself in C (transforming an expression into a statement). This difference manifests itself primarily in two situations:

  • there can never be a semicolon directly before in Pascal whereas it is mandatory in C (unless a block statement is used)
  • the last statement before an or 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.

[edit]

In traditional C, there are only . This is only supported by certain Pascal dialects like MIDletPascal.

In traditional Pascal, there are and . Modern Pascal, like Object Pascal (Delphi, FPC), as well as modern C implementations allow C++ style comments

Identifiers and keywords[edit]

C and Pascal differ in their interpretation of upper and lower case. C is case sensitive while Pascal is not, thus and 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 itself). Examples are if, while, const, for and goto, which are keywords that happen to be common to both languages. In C, the basic built-in type names are also keywords (e.g. int, char) or combinations of keywords (e.g. unsigned char), while in Pascal the built-in type names are predefined normal identifiers.

Definitions, declarations, and blocks[edit]

In Pascal, procedure definitions start with keywords procedure or function and type definitions with type. In C, function definitions are determined by syntactical context while type definitions use the keyword . 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 in C but by punctuation in Pascal.

In Pascal functions, begin and end delimit a block of statements (proper), while C functions use "{" and "}" to delimit a block of statements optionally preceded by declarations. C (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. Pascal is strict that declarations must occur before statements, but allows definitions of types and functions - not only variable declarations - to be encapsulated by function definitions to any level of depth.

Implementation[edit]

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 could be a declaration of to be an object whose type is pointer to , or a statement-expression that multiplies and . The corresponding Pascal fragment is unambiguous without a symbol table.

Simple types[edit]

Integers[edit]

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 (which corresponds to 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 , , , , etc. The exact meaning of the resulting integer type is machine-dependent, however, what can be guaranteed is that is at least 16 bits, is no shorter than and is no longer than .

Subranges[edit]

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):

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

The (only) pre-Standard implementation of C as well as Small-C et al. allowed integer and pointer types to be relatively freely intermixed.

Character types[edit]

In C the character type is which is a kind of integer that is no longer than , . Expressions such as are therefore perfectly legal, as are declarations such as and .

This integer nature of (one byte) is clearly illustrated by declarations such as

unsignedcharuc=255;/* common limit */signedcharsc=-128;/* common negative limit */

Whether the type should be regarded as or by default is up to the implementation.

In Pascal, characters and integers are distinct types. The inbuilt compiler functions and 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 and is a TAB character.

Boolean types[edit]

In Pascal, boolean is an enumerated type. The possible values of boolean are false and true. For conversion to integer, ord is used:

There is no standard function for integer to boolean, however, the conversion is simple in practice:

C has binary valued relational operators (<, >, ==, !=, <=, >=) which may be regarded as boolean in the sense that they always give results which are either zero or one. As all tests (&&, ||, ?:, if, while, etc.) are performed by zero-checks, false is represented by zero, while true is represented by any other value.

Bitwise operations[edit]

C allows using bitwiseoperators 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+[StickyFlag];Status:=Status-[StickyFlag];if(StickyFlaginStatus)then...

or

Pascal:

Status:=StatusorStickyFlag;Status:=StatusandnotStickyFlag;ifStickyFlagandStatus=StickyFlagthen...


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[edit]

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[edit]

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 , but conversion of to (where information may be lost) must be done explicitly via the functions and , which truncate or round off the fraction, respectively.

Enumeration types[edit]

Both C and Pascal include enumeration types. A Pascal example:

typecolor=(red,green,blue);vara:color;

A C example:

enumcolor{red,green,blue};enumcolora;

The behavior of the types in the two languages however is very different. In C, becomes just a synonym for 0, for 1, for 2, and nothing prevents a value outside this range to be assigned to the variable . Furthermore, operations like are strictly forbidden in Pascal; instead you would use . In C, enums can be freely converted to and from ints, but in Pascal, the function ord() must be used to convert from enumerated types to integers, and there is no function to convert from integer to enumerated types.

Structured types[edit]

Array types[edit]

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:

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

vara:array[0..9]ofinteger;

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:

typeTColor=(red,green,blue);(* enumeration *)RGB=array[TColor]of0..255;varpicture:array[1..640,1..480]ofRGBvarpalette:array[byte,0..2]ofbyte

Strings consisting of n (>1) characters are defined as packed arrays with range 1..n.

Arrays and pointers[edit]

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 and the assignment is valid and causes p and a to point to the same array. As the identifier represents a constant address, is not valid however.

While arrays in C are fixed, pointers to them are interchangeable. This flexibility allows C to manipulate any length array using the same code. It also leaves the programmer with the responsibility not to write outside the allocated array, as no checks are built in into the language itself.

In Pascal, arrays are a distinct type from pointers. This makes bounds checking for arrays possible from a compiler perspective. Practically all Pascal compilers support range checking as a compile option. The ability to both have arrays that change length at runtime, and be able to check them under language control, is often termed "dynamic arrays". In Pascal the number of elements in each array type is determined at compile-time and cannot be changed during the execution of the program. Hence, it is not possible to define an array whose length depends in any way on program data.

C has the ability to initialize arrays of arbitrary length. The 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.

staticchar*wordlist[]={"print","out","the","text","message"};staticintlistSize=(sizeof(wordlist)/sizeof(wordlist[0]));inti;for(i=0;i<listSize;i++)puts(wordlist[i]);for(i=listSize-1;i>=0;i--)puts(wordlist[i]);

Pascal has neither array initialization (outside of the case of strings) nor a means of determining arbitrary array sizes at compile time.

One way of implementing the above example in Pascal, but without the automatic size adjustment, is:

constminlist=1;maxlist=5;maxword=7;typelistrange=minlist..maxlist;wordrange=1..maxword;word=recordcontents:packedarray[wordrange]ofchar;length:wordrangeend;wordlist=array[listrange]ofword;vari:integer;words:wordlist;procedureCreateList(varw:wordlist);beginw[1].contents:='print ';w[1].length:=5;w[2].contents:='out ';w[2].length:=3;w[3].contents:='the ';w[3].length:=3;w[4].contents:='text ';w[4].length:=4;w[5].contents:='message';w[5].length:=7;end;beginCreateList(words);fori:=minlisttomaxlistdowithwords[i]doWriteLn(contents:length);fori:=maxlistdowntominlistdowithwords[i]doWriteLn(contents:length)end.

Strings[edit]

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

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

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:

constchar*p;p="the rain in Spain";/* null-terminated */

Null-termination must be manually maintained for string variables stored in arrays (this is often partly handled by library routines).

C does not have built-in string or array assignment, so the string is not actually being transferred to p, but rather p is being made to point to the constant string in memory.

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.[1]

Record types[edit]

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

structa{intb;charc;};
typea=recordb: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:

typer=records:string;c:char;end;varr1:r;beginwithr1dobegins:='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:

structa{unsignedintb:3;unsignedintc:1;};

How much storage is actually 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:

typea=packedrecordb:0..7;c:0..1;end;

Both C and Pascal support records which can include different fields overlapping each other:

uniona{inta;floatb;};
typea=recordcasebooleanoffalse:(a:integer);true:(b:real)end;

Both language processors are free to allocate only as much space for these records as needed to contain the largest type in the union/record.

The biggest difference between C and Pascal is that Pascal supports the explicit use of a "tagfield" for the language processor to determine if the valid component of the variant record is being accessed:

typea=recordcaseq:booleanoffalse:(a:integer);true:(b:real)end;

In this case, the tagfield q must be set to the right state to access the proper parts of the record.

Pointers[edit]

In C, pointers can be made to point at most program entities, including objects or functions:

inta;int*b;int(*compare)(intc,intd);intMyCompare(intc,intd);b=&a;compare=&MyCompare;

In C, since arrays and pointers have a close equivalence, the following are the same:

a=b[5];a=*(b+5);a=*(5+b);a=5[b];

Thus, pointers are often used in C as just another method to access arrays.

To create dynamic data, the library functions and are used to obtain and release dynamic blocks of data. Thus, dynamic memory allocation is not built into the language processor. This is especially valuable when C is being used in operating system kernels or embedded targets as these things are very platform (not just architecture) specific and would require changing the C compiler for each platform (or operating system) that it would be used on.

Pascal doesn't have the same kind of pointers as C, but it does have an indirection operator that covers the most common use of C pointers. Each pointer is bound to a single dynamic data item, and can only be moved by assignment:

typea=^integer;varb,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.

Expressions[edit]

Precedence levels[edit]

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

Pascal

  1. Logical negation:
  2. Multiplicative:
  3. Additive:
  4. Relational:

C

  1. Unary postfix:
  2. Unary prefix:
  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[edit]

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[edit]

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 new symbol was therefore introduced 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 . The code in braces will always execute because the assignment expression 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 which is not supported by Pascal. Also note that now has the value , 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 .

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 has an equivalent in C but not in Pascal.

Implementation issues[edit]

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 doesn't allow the mixing of arithmetic and Boolean variables, and things like this are caught at the semantic level, when it comes time to generate code for them, rather than at the syntax level.

The authors of C took a diametrically opposite approach: they treat the operators as different, and 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[edit]

In Pascal a boolean expression that relies on a particular evaluation ordering (possibly via side-effects in function calls) is, more or less, regarded as an error. The Pascal compiler has the freedom to use whatever ordering it may prefer and must always evaluate the whole expression even if the result can be determined by partial evaluation.

In C, dependence on boolean evaluation order is perfectly legal, and often systematically employed using the and operators together with operators such as , , the comma operator, etc. The and operators thereby function as combinations of logical operators and conditional statements.

Short circuit expression evaluation has been commonly considered an advantage for C because of the "evaluation problem":

vari:integer;a:packedarray[1..10]ofchar;...i:=1;while(i<=10)and(a[i]<>'x')doi:=i+1;...

This seemingly straightforward search is problematic in Pascal because the array access a[i] would be invalid for i equal to 11.

However, in superscalar processors there is a penalty for all jumps because they cause pipeline stalls, and programs created for them are more efficient if jumps are removed where possible. Pascal's ability to evaluate using a fixed formula without jumps can be an advantage with highly optimizing compilers, whereas C has effectively prevented this by requiring short circuit optimization.

Control structures[edit]

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

Pascal has:

  • ifcondthenstmtelsestmt
  • whileconddostmt
  • repeatstmtuntilcond
  • forid := exprtoexprdostmt and forid := exprdowntoexprdostmt
  • caseexprofexpr:stmt; ... expr:stmt; else:stmt; end

C has:

  • if (cond) stmtelsestmt
  • while (cond) stmt
  • dostmtwhile (cond)
  • for (expr; cond; expr) stmt
  • switch (expr) { caseexpr:stmt; ... caseexpr: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: ifexprnotin [A..B] thendefault-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, procedures[edit]

Pascal routines that return a value are called functions; routines that don't return a value are called procedures. All routines in C are called functions; C functions that do not return a value are declared with a return type of 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:

intf(intx,inty);voidk(intq);

are equivalent to the following declarations in Pascal:

functionf(x,y:integer):integer;procedurek(q:integer);

Pascal has two different types of parameters: pass-by-value, and pass-by-reference (VAR).

functionf(vark:integer):integer;x:=f(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:

intf(int*k);//function accepts a pointer as parameterx=f(&t);

C allows for functions to accept a variable number of parameters, known as variadic functions.

intf(inta,...);f(1,2,3,4,5);

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

Additionally Pascal has I/O statements built into the language to handle variable amount of parameters, like . 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 does not have this feature and the localization of variables or functions could only be done for a compilation module wherein the variables or functions would have been declared static.

C allows functions to be indirectly invoked through a function pointer. In the following example, the statement is equivalent to :

#include<string.h>int(*cmpar)(constchar*a,constchar*b);constchar*s1="hello";constchar*s2="world";cmpar=&strcmp;b=(*cmpar)(s1,s2);

Pascal also allows functions and procedures to be passed as parameters to functions or procedures:

procedureShowHex(i:integer);...end;procedureShowInt(i:integer);...end;procedureDemo(procedureShow(i:integer));varj:integer;beginShow(j)end;...Demo(ShowHex);Demo(ShowInt);...

Preprocessor[edit]

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 itself, leading to the syntax we see today.

Pascal constant and type defines are built in, but there were programmers using a preprocessor also with Pascal (sometimes the same one used with C), certainly not as common as with C. Although often pointed out as a "lack" in Pascal, technically C doesn't have program modularity nor macros built in either. It has a simple low level separate compilation facility, however (traditionally using the same generic linker used for assembly language), Pascal does not.

Type escapes[edit]

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

inta;char*p=(char*)(&a);charc=*p;// first byte of a

It may be possible to do something similar in Pascal using an undiscriminated variant record:

vara:integer;b:real;a2c:recordcasebooleanoffalse:(a:integer);true:(b:real);end;end;begina2c.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 aren't required by any Pascal standardizations to share the same address space. Niklaus Wirth, the designer of Pascal, has written about the problematic nature of attempting type escapes using this approach:

"Most implementors of Pascal decided that this checking would be too expensive, enlarging code and deteriorating program efficiency. As a consequence, the variant record became a favourite feature to breach the type system by all programmers in love with tricks, which usually turn into pitfalls and calamities".

Comments

Leave a Reply

Your email address will not be published. Required fields are marked *