

So, the most important question: why use C? Why not stay with Assembly, Forth or Basic? There are many answers to the Question. C is a very compact language: it comprises a minimalistic core of less than fifteen statements. Everything else (including I/O, maths, and many data types) is in external libraries, which can be linked to the program at will. This allows for very small programs and extreme flexibility. Also, C is a high-level language, but, depending on the style and knowledge of the programmer, it may work with all the power of Assembly, or with all the structure and readability of Pascal. This makes it a good choice for writing fast Oric programs easily and quickly. And of course, a language which provides such ample opportunities for puns and jokes has to be good, right?
These articles will assume you are using an 48k Oric-1 or Atmos as your testing platform. Since there is no native Oric C compiler, we use a cross-compiler (i.e. the compiler runs on one platform, and produces code which will run on another). The compiler is David R. Hanson's retargettable ANSI C compiler, lcc. The Oric version, lcc65, runs on IBM PCs and compatibles (DOS or Linux based). You can run your programs either on a real Oric, or on Fabrice Frances' Euphoric emulator.
#include "stdlib.h"
/* The famous Hello World program! */
void main()
{
printf("Hello world!\n");
}
case-sensitive
language. Save it as hello.c. Exit the editor,
and enter the following:
cc65 helloAfter a while, the DOS or Linux prompt will be displayed. Your program is now compiled. Yes, that was all. If you get any error messages, you probably made a typo. Check the file and try again.
Now, let us run the program. A successful compilation will yield a .out file (hello.out in this case). This is a ‘tape’ file. Run Euphoric and load it:
Ready CLOAD"HELLO.OUT" Hello world! ReadySo, there you have it: your first C program on the Oric. Now, let us see why it does what it does.
To understand that, we need an important piece of information: the C compiler is not a single program, but a pipeline of different programs:
In the case of the Oric compiler, the linker (by Vaggelis Blathras) runs between the compiler and assembler, and there is also an extra program which translates the final machine code object file into an Oric ‘tape’ file.
All this might sound a bit too technical (and definitely useless). However, each of these stages has its own command set. In the Hello World program, for example, the first line is handled by the preprocessor.
The #include "stdlib.h" directive instructs the preprocessor to literally include the file stdlib.h at the point in hello.c where the #include command was seen. The preprocessor actually processes and outputs the contents of the specified file, and then goes on with the rest of the original file (of course, #include directives can be nested).
The next line is a comment. Anything between /* and */ is considered a comment. Comments may be located anywhere in a line. They may span lines.
Next, we define a function. A C program is split into
functions, each of which calls other functions. Even the
main program is a function, called 'main'. This function is
automatically called when the program starts.
The curly brackets ('{' and '}') denote the beginning
and end of the body of the function. printf() is a
function (as you might guess by the '()'). It prints the
string passed to it as a parameter (note that C strings are
enclosed in double quotes: "Hello world!\n").
printf() is obviously not defined in our little program. It
is not defined by C itself, either (remember, C has no built-
in functions). It's declared inside stdlib.h
(footnote: in ANSI C, printf() is declared in stdio.h,
the standard input/output functions library. Things are different on the Oric, but they might change
as the Oric C compiler progresses.). This is why
we need to #include "stdlib.h". By the way, the \n
at the end of the string means ‘start a new line’. C actually
translates it to the ASCII code for CR (Carriage Return,
CTRL-M or RETURN).
Another interesting point is the final semicolon (;).
In C, all declarations and statements end with this symbol.
Try not to forget it; the compiler will stop with all sorts of
weird error messages. Since semicolons are used to delimit
declarations and statements, white space (spaces, TABs and
RETURNs) is not important to the compiler. As long as you
use semicolons, you might as well write your whole
program in a single line (I wouldn't recommend it: it makes
debugging a nightmare).
Strange as this may sound, this is all. To make things
easier, there are modifiers which change the width and
format of the four data types. The modifiers are short,
long, signed, and unsigned.
The first two change the
width and range of the data types; the latter two change
between signed and unsigned formats. Here is a table of all
the meaningful combinations of modifiers and data types:
As you can see, this gives a rather impressive collection.
Note that there are defaults to each modifier. If you do not
specify the data type, int is assumed (so it is more
common to write long than long int). The default
format is signed and the default size is normal (no
modifier).
An important concept in C is that, although there are
very concretely defined data types, you are not forced to
obey them: you can store a value of 255 in a signed char.
The compiler might warn you of possible problems,
but will not generate an error. The interpretation of the bit
patterns, however, depends on the variable's data type. So,
when reading the signed char from the previous
example, we will not get 255, but -1 (binary 11111111 =
unsigned 255, but -1 in signed or twos' complement).
Another point (important to BASIC users) is that C
does not allocate variables dynamically: you must declare
them before use. The declaration is a line like one of the
following:
Variable declarations are placed between an open curly
bracket ('{') and the following statement, or outside
function definitions, at the top level of the program. In the
first case, they are local variables: accessible only within
the block they were defined in (i.e. only accessible to the
statements within the curly brackets). Variables defined at
the top level are global: they are available to all your
program.
3 Simple Data Types and Variables
Like most high-level languages, C has its own set of data
types. Only simple data types are defined by C: all other
data types can be derived from simple ones. They are
defined in (guess what) libraries. Here is a table of simple
data types and their widths in bits.
Type
Description
Bits
char
A single byte
8
int
A signed integer
16/32
float
Floating point number
32
double
Double precision float
64
Modified Type
Bits
Range
char
signed char
8
-128 ... 127
unsigned char
8
0 ... 255
int
signed int
16/32
-32768 ... 32767 or
-2147483649 ... 2147483648
unsigned int
16/32
0 ... 65535 or
0 ... 4294967295
short int
signed short int
8/16
-128 ... 127 or
-32768 ... 32767
unsigned short int
8/16
0 ... 255 or
0 ... 65535
long int
signed long int
32
-2147483649 ... 2147483648
unsigned long int
32
0 ... 4294967295
float
32
-3.4E-38 ... 3.4E+38
double
64
-1.7E-308 ... 1.7E+308
long double
64
-3.4E-4932 ... 1.1E+4932
char x, y; /* x and y are chars */
int i; /* i is an int */
float X; /* note that x is NOT X */
long a=15; /* variable initialisation */