LEARNING TO C
A programming language more powerful than BASIC
by THOMAS McNAMEE
Higher-level languages have traditionally been associated with large mainframe and mini computers, but they're now becoming increasing available to microcomputer owners. These languages present the Atari owner with a wide array of problem-solving tools. The C language, in particular, is a fascinating and useful addition to any programmer's language library.
Since C is a compiled language, composition is fairly involved; the steps include editing, compilation, assembly and testing. Think of C as the next step above a macro assembler. Its operators, functions, and keywords handle a lot of the messier tasks of assembly-language programming, but the language itself doesn't hamper your ability to use the full power of your Atari.
Among the best features of tile C language are the following:
- C compiles down to the machine-code level. It is engineered to produce compact, but not necessarily fast code. Even so programs written in C typically run as much as ten times faster than equivalent programs in BASIC.
- It is designed for transportability. Although each compiler contains implementation-specific features, most programs are compatiple with each other.
- It is extensible, and, in fact, has few intrinsic functions that are sensitive to their environment, such as I/O(input and output) are either written by the user or supplied with the compiler in the form of "libraries."
- Like macro assemblers, C encourages the creation of libraries of user-defined functions. These can be included in subsequent programs without rewriting.
C is a structured language. From a beginner's viewpoint, this is desirable, because programs in C are constructed of small, tested modules called functions. Functions are composed of statements, which can be made up of functions and/or expressions.
The C language also uses variables. Their declaration, syntax, and locality can be confusing to a beginning programmer, but, unless otherwise stated, they are "born" when and where they're created, and they "die" when they leave their home statement (where they were declared). Parameters are passed to functions, and results are returned to the calling functions. The following is an example of a function defined in C:
1 /* LEN function */
2 /*
3 Call with:LEN(string)
4 */
5 LEN(BUFF)
6 CHAR *BUFF;
7 $(
8 INT CNT;
9 CNT=O;
1O WHILE (*BUFF+ + !=0)
11 ++CNT;
12 RETURN(CNT-1);
13 $)
Lines I-4 are comment lines, and are similar to REM lines in BASIC. They are ignored by the compiler. Line 5 is the function-name declaration. The name to be assigned to the passed parameter is RUFF. Note that this name does not have to match the name of the string in BUFF when LEN is called; the variable name BUFF "lives" only inside LEN. C stores strings either as literals (in quotes) or in a CHAR array. In function calls, C passes only the address of the first character. The rest of the characters are stored sequentially, and the string ends with a zero.
Line 6 is a variable-type declartion. All function parameters must be declared by type. In this case, the asterisk proceeding the parameter name (BUFF) means that it is going to be used as a pointer to an array. The value of BUFF is the address of the array, and the value of *BUFF is the character that BUFF points to. Pointers such as this are powerful tools for string handling and array manipulation. The semicolon at the end of the line indicates that this is a complete statement.
Line 7 indicates that a group of statments is to follow. The $) in line 13 indicates the end of the group of statements.
Wiithin this group of statements, a variable is needed to count characters. Lines 8 and 9 declare and initialize the variable CNT, which ceases to exist when it encounters the $).
Line 10 evaluates *BUFF to see if it points to the end-of-string zero. The ! = means "is not equal to," while the + + means increment. When + + precedes a variable, the value is taken after the increment. In line 10, however, the order is reversed, so the value is taken before the increment. Because of this, *BUFF already points to the next character.
Line 11 increments CNT if the character pointed to by *BUFF does not equal zero. In line 12, RETURN returns the value in parentheses to the calling routine. Since the value of CNT includes the trailing zero, we decrement it by one before returning. Line 13, which contains the closing delimiter, indicates the end of the function.
C/65 BY OSS
I use a C implementation called C/65, which is produced by Optimized Systems Software (OSS). It's a "small C," or a subset of the C language used on larger computers. Some of C's best features, such as "for" and "switch" statements, are missing from this implementation, and only "char" (eight-bit) and "int" (16-bit) data types are allowed.
Since C/65 produces assembler source code, OSS's MAC/65 assembler is necessary to assemble the source and create an executable object file. This assembler is expensive but it is a powerful macro assembler, text editor and debugger, so you get your money's worth. The documentation for C/65 and MAC/65 amounts to almost 300 pages of text, and all of it should be read carefully.
However, if you really want to get into C, you'll need to do more reading and research. I've found that The C Programming Language by Kernighan and Richie is one of the best reference books on the subject. It's a bit advanced for the beginner, though, so I also recommend that you read The C Primer by Hancock and Krieger, which is written for the beginning C programmer. It takes a while to get the hang of C, but once you've built a good foundation you'll find that it's easy to learn the rest. And well worth your time and effort.
Thomas McNamee is a software engineer for ManTech International in Alexandria, Virginia. He programs in FORTH,C,BASIC and 6502 assembly language, and has written for a number of computer publications.