ALL AT C - ANOTHER C TUTORIAL By Andy P++ Do you want to learn to program in C? Or maybe you would like to understand the Intuition Reference manual? Or perhaps you are just curious about why the gurus at Commodore decided it would be a "good thing" to use C for major parts of the software development for the Amiga. Then read on. In this series of articles I hope to introduce all the major features of C in the context of the Amiga. I assume that most readers are familiar with at least some form of programming... even BASIC! What is C? Wow! the tricky stuff first. Well, C is the third letter of the alphabet (our alphabet anyway), but it is also a name for a programming language. The language was developed by a small team at Bell Laboratories. It was created in response to a need for a language to implement a new operating system, UNIX. The language itself was based on a previous language developed by Ken Thompson in 1970 called B (hence C... now you know!). B itself owed a lot to a previous language, BCPL, developed at Cambridge University in 1967 by Martin Richards. BCPL stands for Basic CPL (Combined Programming Language). It is a curious coincidence that, apart from assembler, the Amigas system software was all written either in C or BCPL! OK, but what makes C different from BASIC or assembler? Lots, but it may help to categorise C as a low- level language, some have even said a structured assembler. BASIC is a much higher level language in the sense that the user is much more insulated from the hardware. You BASIC programmers out there (there are a few left I've been told) are going to have a much harder time with C than those of you who have hacked it at the machine level. Another thing that distinguishes C from BASIC is that C is almost exclusively compiled. That is that the program is written first, then translated to machine code, then run. I say almost exclusively since I have seen interpreted C advertised... this seems a case of the worst of both worlds! Although closer in spirit to assembler, C is more of a symbolic language, representing basic operations in a (nearly) portable way. OK, Quit the bovine excrement, show us a program Alright, you asked for it... main() { printf( "Hello world\n"); } That was a complete program to output the message 'Hello world' followed by a newline to the screen. To BASIC boys, yes I know it's a bit verbose, to assembler hackers, yes I know it's a bit brief. Although easy to write you will go through 7 kinds of hell trying to compile and run this. It is a characteristic of this type of programming (as opposed to BASIC) that a short program is nearly as tricky as a medium sized one. Let me try to explain the elements of this "simple" program. The word "main()" introduces the start of the program, it says "this is the first thing to do". Later I will explain about functions, and the meaning of the empty brackets should become clear. The curly brackets "{" and "}" are used to collect together a set of things, in this case a set of "statements" (equivalent to lines of basic code, or lines of assembler). The only statement in this program is: printf("Hello World\n"); This says print the text 'Hello world' followed by a newline ( '\n' is C-speak for a newline). Most impressive, but there must be more Well yes, but to explain much more I will have to go through a few fundamentals of C. At this point things will probably seem to be a bit disconnected but I will try to show an example at the end to draw the threads together. Data types C can handle various sorts of data. The principle simple types are integers (0,1,2 etc, even -1, -2 and so on if you can handle that), characters ( A, B, C and so on) and floating point numbers (24.678, 0.00045, and many others). These are the basic sorts of thing that C deals with, and it has a name for each of them. There are other types but they are either variations on a theme (for example signed or unsigned numbers), or collections of the simple types (arrays etc.). In common with assembler, C insists that the person writing the program tells the compiler about the data used, its name and its type. Such named pieces of data are called "variables", each of which can contain a range of values determined by the type. The predefined simple types are: TYPE DESCRIPTION RANGE int signed integers -2147483648 to 2147483647 char a character or byte -128 to 127 float a "real" number +/-10E-37 to +/-10E+38 A few explanations here... Characters are represented by a small number corresponding to the ASCII code, eg 'A' is 65. For the assembler folks, an int is held in 32 bits, a char in 8 bits and a float in 32 bits. Until further notice I will ignore floats, as in many years of programming I have very rarely needed them. Given these types, if you want to name a variable you simply precede the name you want to use with the name of the type, for example: int a; Says the variable 'a' is an integer. C allows quite a lot of flexibility in naming variables, lower case, upper case, numbers and underscores, although names must start with a letter or underscore. So: fred, Quite_A_Long_Name, A12343, _43 are all OK names. 1Henry, 128, &fred, xy#z would all be rejected. Statements As well as data, a complete program uses statements to tell the computer what to do. In C there are a range of statement types, we introduce a couple here. Assignment: To change the value of a variable we usually use an assignment statement. This uses the equals sign. Assume we have a variable called 'nissan' that is of type 'int', that is it can contain integers. Then to put the value 4096 in it we use the statement: nissan = 4096; The semicolon says, "this is the end of this statement". What comes after the '=' sign does not have to be a single thing, it could be an expression: nissan = 4096 + 17; or even reference another variable, say 'mitsubishi': nissan = 4096 - mitsubishi; While loop: The simplest loop in C is the "while" loop. It allows a statement or group of statements to be repeated while some condition is true. This looks like: while( condition) statement; Or if we want to loop through more than one statement use the curly brackets: while( condition) { statement1; statement2; } Comments To help make C code more readable (some would say "less unreadable"!) comments may be interspersed with the code at most places where a space could be used. A comment is distinguished by being enclosed in comment brackets, /* .... */. The compiler ignores comments entirely, and unlike some interpreted languages comments do not slow down, or make bigger, your program so feel free to express yourself. A more complete example Using what we now know, lets write a simple program to print out the numbers 1 to 5 and the cubes of these numbers. main() /* Remember, this says start here */ { /* Declare an integer variable */ int a_number; /* And another for its cube */ int cube; /* Initialise a number */ a_number = 1; while ( a_number <= 5) { /* Calculate the cube */ cube = a_number * a_number * a_number; /* And print the result */ printf("%d cubed is %d\n", a_number, cube); /* Go on to the next number */ a_number = a_number + 1; } } Quick word of explanation on the "printf" line. "printf" is the nearest equivalent C has to BASICs PRINT command. It is rather more ugly to look at but can do very similar (and in some cases more sophisticated) things. Rather than the simple print of a string we did before, now we are printing numbers inside a string. Wherever the "%d" is found, the next number in the list that follows is displayed. The output of that program will therefore look like: 1 cubed is 1 2 cubed is 8 3 cubed is 27 4 cubed is 64 5 cubed is 125 That seemed a bit windy, there will be those of you out there saying, "Yes, but I thought C was terse and obscure". You would of course be right in a sense as it largely depends on the programmer. Putting my C-hacker hat on we can rewrite the previous program as: main() { int i=0; while( ++i < 6) printf( "%d cubed is %d\n", i, i*i*i); } This introduces only one really new concept (apart from the fact that C programmers take an odd pleasure in being needlessly obscure) and that is the increment operator, the double plus sign. This operator is worthy of a place in the "black museum" of programming. Its advantage is in producing very terse programs that are easily translated to quite terse object programs. Its disadvantage is that badly used it can make a program very difficult to understand. The effect of the ++ operator is twofold. When placed in front of a variable it first adds one to the variable, and then returns that incremented value. Assembler programmers will understand the ++ operator as being very similar to an INC instruction. Most high level languages do not have a similar concept so the C statement: charlie = ++fred; would in most ordinary languages be something like: fred = fred + 1; charlie = fred; Note that both examples there were in fact valid C and if you don't like them you can always avoid the use of the ++ operator. Unfortunately you will probably need to read code using it. Before I wrap up this first lesson (watch out K&R, here I come!) lets just go through the full list of simple data types (I previously simplified things). signed char A character in the range -128 to +127, also often known simply as "char" unsigned char A character in the range 0 to 255. signed short int An integer in the range -32768 to +32767. unsigned short int An integer in the range 0 to 65535. signed int An integer in the range 2147483648 to 2147483647, also known simply as "int". unsigned int An integer in the range 0 to 4294987295. signed long int As per "signed int". unsigned long int As per "unsigned int". float A floating point number in the range +/-10E-37 to +/- 10E+38. A low precision floating point number. double A floating point number in the range +/-10E-307 to +/-10E+308. A high precision floating point number. pointer A memory address in the range 0 to 0xFFFFFFFF (that was a hex number, 32 bits worth). That was all the possibilities for the Lattice compiler. All halfway decent C compilers support the same set of simple types although the precise ranges and what "int" and "char" default to may vary. You can expect all compilers for the 68000 (which the Amiga uses) would have a similar set of ranges and defaults. Well, thats all folks for lesson 1. In lesson 2 we will ponder the mysteries of the full range of C operators, complex data types and pointers. If you can stick with it for that long you deserve the C order of merit. End.