AdVANCEd C PROGRAMMiNG
ON THE ATARi 8-BiT, PART 1
ON THE ATARi 8-BiT, PART 1
by MARk MiIIER, AC CONTRibUTiNG AUTHOR
AC thanks the Front Range Atari User's Group in Fort Collins, CO for permission to use this article.
A Programmer's Beginnings
I've owned an Atari 130XE for four years and have programmed on 8-bit computers since 1981. Over the past three years in college I've also programmed mainframe and minicomputers. One thing I admire about these more powerful computers is their ability to compile and run programs in languages like Pascal, C, and FORTRAN. I like Pascal and C a lot more than the languages I used to think an 8-bit computer was limited to.
You 8-bitters know which ones I'm talking about: BASIC (the major language for all 8-bits), assembly language (the language used when you want to get it done fast with a lot of power), LOGO (the language that makes computer graphics easy), and FORTH (I haven't used this one, but reportedly it's close to assembly language). I've programmed in BASIC and LOGO, but I generally avoid 6502 assembly language with a ten-foot pole. Assembly, in my view, is too laborious and risky for what I usually want to do on my 8-bit.
I learned Pascal in high school (using Apple Pascal) and continued in my freshman year at CSU, using standard Pascal on a mainframe. Once I saw I could break up my programs into procedures and functions, and use more powerful data types than was available in BASIC, I got hooked on it! I like the Pascal approach to programming because I can write more powerful programs, and I can do tasks modularly within a program which makes it more organized and easier to modify. No more spaghetti code for me! After awhile, I was doing more stuff' in Pascal on the minicomputers at school than I was in BASIC on my own computer. I really hungered for the ability to use Pascal on my 8-bit. But until recently, whenever I wanted to program on my 8-bit I was limited to BASIC. I considered getting the Action! language, but it was too pricey for me, and I'd heard it was hard to learn. I wanted a language I could learn on my 8-bit and use at school as well.
I considered Pascal. I knew of three Pascal compilers for the Atari 8-bits: Atari Pascal, Kyan, and Draper. Draper was interesting since it is Shareware. I got a copy of Draper Pascal but was disappointed by its restrictions. Later I discovered that most of the Atari 8bit compiled languages have severe limitations compared to their standard counterparts. These languages have many of the same limitations as Draper. It doesn't support multi-dimensional arrays in the true sense of the word (you can only have a maximum of two dimensions for an array), you can only return a value of type integer from a function, and no pointers to anything are allowed. In a nutshell, Draper and many of the 8-bit compiled languages are, in my opinion, functionally more advanced BASICs.
C'eeing the Light
Another option was a C compiler. I had just taken a course in C last year, and it was a language I liked right off since it's more powerful than Pascal. I used to think a C compiler wasn't possible on an 8-bit due to the size of such a compiler and all the required libraries. When I got into college, I was surprised to learn there were two C compilers for the Atari 8-bit: Deep Blue C and Lightspeed C. Both are commercial products available from B&C ComputerVisions. One day I found three more C compilers for the 8-bit on the Internet ftp site at the University of Michigan called atari.archive.umich.edu. These compilers were CC8, Ace C, and CC65.
CC65 is a cross-compiler written by John Dunning, moderator of Internet's Info-Atari8 Digest. It's designed to run on a more powerful computer- such as a Unix system- and generates machine code the Atari 8-bit understands. Once a program is compiled with CC65, the object code can be downloaded to and run on an 8-bit. It supports many standard features of C. It looks like it was made so that source code compiled on a regular C compiler could also be compiled on CC65 very easily. The package is made up of several programs: CC65, the compiler; RA65, a relocatable-code assembler; LINK65,the linker; and LIBR65, the library manager. The cross-compiler version is written entirely in C itself. The 8-bit version (already compiled into binaries) and the cross-compiler version (in source-code form) of this package are available at atari.archive.umich.edu, in the directory atari/8bit/cc65.
CC65: Not Bad!
The 8-bit version was actually made by compiling itself! In other words, the 8-bit version of CC65, RA65, LINK65, and LIBR65 were all compiled, assembled, and linked by CC65, RA65, and LINK65 themselves, on some other system. Since the package is designed to generate Atari 8-bit machine code, it's only natural that the 8-bit version would be created this way. I wish it were re-coded in assembly though, like the other 8-bit C compilers, since the 8-bit versions of the programs are very large. But it's neat to know that CC65 supports enough features of C to actually compile a full compiler system on its own.
The features supported by CC65 are: pointers to pointers, pointers to functions etc., structs, unions, but no enums (except in the cross-compiler version), and no float types. Multi-dimensional arrays can be declared. Variables can be declared int, char, long, and short. It has some standard libraries and library functions, like <stdio.h>, fprintf(), gets(), fopen(), etc. It even has a small interface that lets users with non-CLI DOSes pass arguments to a program, as though they were using the argv and argc parameters in main()! The standard global input/output variables stdin, stdout, and stderr are supported, so you can get and put stuff from/to the user in the standard C way, like you would when using a regular C compiler.
On the negative side, CC65 doesn't presently support Atari-specific features such as graphics and sound. When I looked in detail at the library functions' source code, it looked like floating-point numbers and operations; graphics and sound could be supported if more functions were added. It looks like Dunning designed this compiler with the idea of expanding it in the future, since there are some things in the source code that are already set up for graphics and sound, and maybe even floating-point arithmetic. Only there aren't any functions in the library yet that take advantage of this.
In the the Jan./Feb. 1991 issue of Current Notes, on p.67 there's a short blurb on yet another commercial C compiler for the 8-bit from DataQue. This is the same outfit that makes the Turbo-816 modification. It's called Turbo-C8, and reportedly it's a full implementation of ANSI C (a C language developed according to rules laid down by the American National Standards Institute) on a bankswitching cartridge! It doesn't say whether it's specifically for 8-bits that have the T-816 modification or not. I would assume it was designed to run on either an unmodified or modified 8-bit, since that's how DataQue designed their other applications. [Editor's Note. to the best of our knowledge Turbo-C8 was never released commercially due to problems implementing ANSI structs and unions. Chuck Steinman, where are you?]
I'm mainly going to concentrate on the CC8 compiler from here on, since that's what I've used the most. The documentation for CC8 suggests that you also get Ace C for its linker and libraries, which CCS lacks. [The commercial Lightspeed C is actually an improved version of Ace C, by the same author. -Ed.] All three C compilers at atari.archive are public domain. John Palevich and Steve Kennedy are the authors of CC8.
CC8: My Favorite!
CC8 converts your C source code into relocatable P-code. Using the Ace C linker and a small text file specifying what files are to be linked, an executable file is created. It turns out you can also use the linker and libraries of Deep Blue C and Lightspeed C with CC8 P-code files because the compilers generate the same type of P-code. Ace C also comes with an optimizer that works on P-code files.
The documentation of CCS is full of surprises. Even though CC8 is PD, it supports many functions of "standard" C- some of which are not supported even in the commercial compilers mentioned above! "Standard C" is kind of an oxymoron (a phrase that contradicts itself), since there are many variations of the C language around, even on the major computer systems. ANSI has agreed on a standard for C so there is now a recognized standard. Thus the lure of something like Turbo-C8: a full ANSI C implementation adhering to the official standards, for the Atari 8bit. Wouldn't it be nice!
Neat Stuff In CC8
Here's the rundown on features of standard C supported by CC8, along with a description of the significance of those features:
- CC8 supports all preprocessor functions of standard C except for #line. The preprocessor functions supported include LINE (for current line number) and FILE (for current filename). (A C compiler goes through two phases. The first phase is the preprocessing phase where symbols can be defined to represent certain things. Other source code can be included, with or without certain conditions. This is useful for bringing in general routines that can be used in more than one program. Macros can be created to shorten the length of programming and source code.)
- Pointers to pointers, pointers to functions, arrays of pointers to functions, etc. may be declared. (There are data types in C called pointers. All variables that are declared of this type are just addresses to memory locations that hold a value, or executable code. So a pointer may actually contain the starting address of a function. For you assembly programmers this should ring a bell.)
- Multi-dimensional arrays may be declared using char, int, struct, union, and enum data types. Variables can be declared static and extern. The register storage class may be used. (A "struct" is a collection of variables that can be of different data types. Structs haves many paralats to elements of a database program. A struct could be considered a record, and the variables inside could be called fields of the record. As a matter of fact, the variables inside a struct are called fields. A "union" is like a struct, except only one field can store information at any one time. It was invented to save space. "Enum" lets you sequentially define a set of symbols to have numeric values. You could assign the color value of blue to the symbol "blue", so that throughout the program you can use "blue" in place of that value. Enum data gets converted to integers upon compilation in CC8. "Static": when a variable is declared static, it means the location in memory the variable points to never changes. Static variables can produce interesting effects. For example, if a static variable is inside a function, it retains its value after the function is exited. When that function is re-entered, it will still have that same value. "Extern" lets you tell the compiler about a declaration that's coming up, since compilers read source code from top to bottom. Thus you can use the variable or function before it's declared, and the compiler won't yell at you for not declaring it in advance. "Register": this is termed a storage "class" because register values aren't stored the same way as other variables. Values stored in a variable of storage class register are stored in a hardware register of the computer, and operations can be done faster on them. In CC8, anything declared "register" is translated to an integer since the 6502 only has a few registers.)
More CC8 Goodies
- Values of type int, char, or pointer (to anything) may be returned from functions.
- Local variables may be declared at the beginning of compound statements. But no two local variables (in a function) can have the same name.
- Recursion. Functions can call themselves.
- The sizeof function; typecasts may be used. (The "sizeof" function returns the size of a variable, of a certain type, in bytes. Typecasts are a way of assuring that what is produced by some thing on the right side of an '=' is of a certain data type, so type conflicts won't occur.)
- Expressions follow operator precedence. All operators follow precedence, including the ++, --,* (pointer indirection), & (get address of variable), etc., not just mathematical operators. (There are a lot more operators in C than just the mathematical ones you're already familiar with. There are operators to determine boolean values for conditional statements, manipulate the bits of a variable, etc. All these operators have certain precedence levels. Sometimes parentheses are used in expressions employing these operators in order to yield the desired result.)
- Standard flow control functions: for, while, do-loops, if, ifelse, switch. ("For", "while", and "do"-loops are programming loop structures. "Switch" is like a shorthand for making multiple IFTHEN statements.)
- Initialization of global variables of type char, int, pointer, array, struct, union, and enum, as in: char q[l0]="hello";. An example of aggregate variable types is: char "weekdays=$( "Mon.", "Tues.", "Wed.", "Thu.", "Fri." $); the '$('and '$)' markers represent left and right curly brackets in CC8 since ATASCII doesn't have those characters. CC8 does understand the ATASCII equivalents of the left and right curlies, but the listed sourcecode doesn't look as nice. (It's possible in C to initialize a variable right when it's declared, as in the above examples. If you like, you may not even need to specify the size of an array. Global variables are like the variables used in BASIC. Once they're declared, they can be used anywhere. This is the opposite of local variables which are declared inside of functions or compound statements and don't exist outside those domains.)
- goto's and labels. (To the chagrin of programmers who believe in structured programming, C supports a goto statement that lets you jump to another location. But you can't do it using a line number. You need to specify a label, and put the label at the location in the source code you want to jump to. Programmers favoring the "structured" approach usually avoid using goto's.)
Next issue: Mark reviews some limitations of CC8 and proceeds with programming tips.
[Editor's Note: if readers express sufficient interest in CC8, we'll consider putting it on a future AC Software Disk. At the moment we're reluctant to do so because the aggregate UNARCed files of CCS and related Ace C libraries are enormous and could consume an estimated 140K of our 180K disk filespace. -BP]