Guest beers: (1) Introduction to data types, (2) Standard predefined types, (3) Range and precision with respect to numeric types, (4) Pointers/Access values and (5) Type declarations:
The type of a data item defines:
The process of associating a type with a data item is referred to as a data declaration.
2. Scaler and Compound types. Scalar types define data items that can be expressed as single values (e.g. numbers and characters). Compound types (also referred to as composite or complex types) define data items that comprise several individual values. Scaler types are generally pre-defined, while compound types are often programmer-defined.
3. Discrete and Non-discrete types. Discrete types (also refered to as linear or ordinal tpes) are types for which each value (except its minimum and maximum) has a predecessor and a successor value. The opposite are referred to as non-discrete types.
4. Basic and Higher Level types. Basic types (also refered to as a simple types or type primitives) are the standard scaler predefined types that one would expect to find ready for imediate use in any imperative programming language. Higher level types are then made up from such basic types or other existing higher level types. Higher level types are not necessarily programmer defined - for example many imperative languages include a string high-level type.
Every imperative languages supports a number of standard basic data types:
Data item | Ada | C | Pascal |
---|---|---|---|
Character (integers in the range 0..255) | character | char | char |
Integer | integer | int | integer |
Real or floating point number | float | float | real |
Logical type | boolean | boolean | |
Charcater string | string | text | |
Void | void |
Note that the type void supported by C indicates a type whose value corresponds to only 0 bits in memory.
Ada:
with CS_IO; use CS_IO; procedure INIT_ADA is NUM_A: integer:= 1; NUM_B: integer:= 2; NUM_C, NUM_D: integer:= 3; NUM_E: integer:= C; NUM_F: integer:= C+1; begin put(NUM_A);put(NUM_B);new_line; put(NUM_C);put(NUM_D);new_line; put(NUM_E);put(NUM_F);new_line; end INIT_ADA;
C:
#includevoid main(void) { int num_a = 1, num_b = 2; int num_c = 3, num_d = 3; int num_e = num_c; int num_f = num_c+1; printf("a = %d, b = %d\n",num_a,num_b); printf("c = %d, d = %d\n",num_c,num_d); printf("e = %d, f = %d\n",num_e,num_f); }
Note that Ada supports multiple initialisation (e.g. NUM_C, NUM_D: integer:= 3;) while C does not.
Adjectives are used to specify classes of numeric types. Some C examples are given below:
Adjectives and Type | Size in Bits | Values |
---|---|---|
unsigned short int | 16 | 0 to 65535 |
signed short int, short int, short | 16 | -32768 to 32767 |
unsigned long int | 32 | 0 to 4294967296 |
signed long int, long int, long, int | 32 | -214748368 to 2147483647 |
float | 32 | Real number to approx 6 sig. figs. |
double | 64 | Real number to approx 15 sig. figs. |
long double | 128 | Real number to approx 33 sig. figs. |
The most high level approach to defining range/precision is through explicit specification. Example imperative languages where this is supported include Ada and Pascal. In Ada this is achieved using a general type declaration statement as follows:
type SCORE is range 0 .. 100; type TEMPERATURE is digits 4; type PERCENTAGE is digits 4 range 0.0 .. 100.0;
Ada example program using explicit range and precision specification:
with TEXT_IO; use TEXT_IO; procedure PERCENTAGE is type PERCENTAGE is digits 4 range 0.0 .. 100.0; package PERCENTAGE_INOUT is new float_io(PERCENTAGE); use PERCENTAGE_INOUT; SCORE1, SCORE2: PERCENTAGE; begin get(SCORE1);get(SCORE2); put(SCORE1);put(SCORE2); new_line; end PERCENTAGE;
Many imperative languages (Ada, Pascal) allow the programmer to access constants that give information about the default properties of a given type. In Ada such constants are referred to as attributes. Some common (Ada) attributes include:
Type | Attributes |
---|---|
integer | first, last |
float | digits, small, large |
character | pos, val |
Example usage:
with CS_IO; use CS_IO; procedure ATTRIBUTES is begin -- Lowest integer put("first = "); put(integer'first); new_line; -- Highest integer put("last = "); put(integer'last); new_line; -- Number of digits for floating point number (precission) put("digits = "); put(float'digits); new_line; -- Lowest floating point number put("small = "); put(float'small); new_line; -- Highest floating point number put("large = "); put(float'large); new_line; -- Code for letter A put("pos(A) = "); put(character'pos('A')); new_line; -- Letter associated with code 66 put("val(66) = "); put(character'val(66)); new_line; end ATTRIBUTES;
Note that the attributes first and last specify the default Ada integer range, whilst the attributes small and large specify the default Ada floating point range. The attribute digits then specifies the default precision for Ada floating point numbers.
Pointers (access values in Ada) are variables that have as their value an address, i.e. a reference to another data object.
* (Asterisk) & (Ampersand)
int *numberPtr;
*numberPtr = *numberPtr + 1;
numberPtr = &xIn this case x is referred to as a reference variable.
Consider the following example:
#include <stdio.h> void main(void) { int number, *numberPtr; scanf("%d",&number); numberPtr = &number; printf("Value of number = %d\n",number); printf("Address of number = %d\n",&number); printf("Value of numberPtr = %d\n",numberPtr); printf("Address of numberPtr = %d\n",&numberPtr); printf("Value pointed at by numberPtr = %d\n",*numberPtr); }
Note that the address of number and the value of numberPtr are the same. If the result of running the above program (with number set to 2) were:
Value of number = 2 Address of number = 2063808352 Value of numberPtr = 2063808352 Address of numberPtr = 2063808356 Value pointed at by numberPtr = 2
We can illustrate this as follows:
with CS_IO; use CS_IO; procedure ACCESS is type INTEGERPTR is access integer; INT_PTR: INTEGERPTR:= new integer'(2); begin put(INT_PTR.ALL); new_line; end ACCESS;
Note that the variable INT_PTR is referred to as an access variable.
Programmer-defined types are defined using a type declaration statement. This binds a "new" type definition with a type name (remember that a data item declaration statement binds a data item name to a type definition). Type declaration statements have the general form:
type <TYPE_NAME> is <TYPE DEFINITION> ; <TYPE_NAME> = <TYPE DEFINITION> ; typedef <TYPE_NAME> <TYPE DEFINITION> ;
In Ada, Pascal and C. Note that in Pascal type declarations must be grouped together in a type declaration section which must be preceded by a const declaration section (if any), and followed by a var declaration section (again if any).
A type declaration statement can also be used to rename an existing type, for example to use a more descriptive (application dependent) type name for a particular type. This offers advantages of both Clarity and Brevity. Examples:
subtype REAL_T is float; NUMBER: REAL_T;
typedef float REAL_T, *REAL_T_PTR; REAL_T number; REAL_T_PTR numberPtr;
In both of the above examples an alternative name for the pre-defined type float has been declared.
Given a particular application it is sometimes also useful to characterise a sub-set of values of some other pre-existing type. This is supported by languages such as Ada (but not C) where a subtype declaration statement is used as follows:
subtype DAY_NUMBER_T is integer range 1..31; DAY: DAY_NUMBER_T:= 10;
Here the type DAY_NUMBER_T is declared as a "sub-type" of the type integer (the new types range is a sub-set of that available for the supper-type). A similar effect can be achieved in Pascal (although the languages does not specifically support a "subtype" statement).
OPTICS: Left - return to imperative home page. Right - continue.
Created and maintained by Frans Coenen. Last updated 03 July 2001