Friday, August 17, 2007

C programming

C Programming :: Introduction
C is a simple programming language with few keywords and a relatively simple to understand syntax.
C is also useless. C itself has no input/output commands, doesn't have support for strings as a fundamental (atomic) data type. No useful math functions built in.
Because C is useless by itself, it requires the use of libraries. This increases the complexity of C. The issue of standard libraries is resolved through the use of ANSI libraries and other methods.
C Programming :: Hello, World
Let's give a go at a very simple program that prints out "Hello World" to standard out (usually your monitor). We'll call our little program hello.c. #include main() { printf("Hello, world!\n"); return 0; }
What?!?!? What's all this junk just to print out Hello, World? Let's see what's happening:
#include - Tells the compiler to include this header file for compilation.
What is a header file? They contain prototypes and other compiler/pre-processor directives. Prototypes are basic abstract function definitions. More on these later...
Some common header files are stdio.h, stdlib.h, unistd.h, math.h.
main() - This is a function, in particular the main block.
{ } - These curly braces are equivalent to stating "block begin" and "block end". These can be used at many places, such as if and switch.
printf() - Ah... the actual print statement. Thankfully we have the header file stdio.h! But what does it do? How is it defined?
return 0 - What's this? Who knows!
Seems like trying to figure all this out is just way too confusing. Let's break things up one at at time:
The return 0 statement. Seems like we are trying to give something back, and it is an integer. Maybe if we modified our main function definition: int main() Ok, now we are saying that our main function will be returning an integer! So remember, you should always explicitly declare the return type on the function!
Something is still a little fishy... I remember that 0 implied false... so isn't it returning that an int signifying a bad result? Thankfully there is a simple solution to this. Let's add #include to our includes. Let's change our return statement to return EXIT_SUCCESS;. Now it makes sense!
Let's take a look at printf. Hmm... I wonder what the prototype for printf is. Utilizing the man pages we see that printf is: int printf(const char *format, ...); printf returns an int. The man pages say that printf returns the number of characters printed. Now you wonder, who cares? Why should you care about this? It is good programming practice to ALWAYS check for return values. It will not only make your program more readable, but in the end it will make your programs less error prone. But in this particular case, we don't really need it. So we cast the function's return to (void). fprintf, fflush, and exit are the only functions where you should do this. More on this later when we get to I/O. For now, let's just void the return value.
What about documentation? We should probably doc some of our code so that other people can understand what we are doing. Comments in the C89 standard are noted by: /* */. The comment begins with /* and ends with */.
Let's see our new improved code! #include #include /* Main Function * Purpose: Controls our program, prints Hello, World! * Input: None * Output: Returns Exit Status */ int main() { (void)printf("Hello, world!\n"); return EXIT_SUCCESS; }
Much better! The KEY POINT of this whole introduction is to show you the fundamental difference between correctness and understandability. If you lose understandability in an attempt to gain correctness, you will lose in the end. Always place understandability as a priority ABOVE correctness. In the end, if a program is more understandable, the chances it can be fixed correctly will be much higher. You should always document your program. If you try to make your program itself more understandable, you stand less of a chance of screwing up your program later.
C Programming :: A Glimpse at Compilation
You will most likely be using the GNU C compiler, gcc. Most environments will have the cc variable set which is much more suitable when using Makefiles. A superficial look at compiling would entail: gcc file.c But is this what you really want? We get a file called a.out in our directory. This is because you aren't specifying the correct compiler options. Taking the theory of "that which is learned first is learned best", compile your programs using the "anal retentive" flags. This will not only catch more errors at compile time, but will help you create a program with less errors at run time. The recommended options to include while compiling are:
-ansi: Use ANSI C
-pedantic: Issue all warnings according to strict ANSI standard C
-Wall: Turn on all Warnings. ALWAYS use this. You will benefit from it.
-O2: Optimization Level 2, nearly all supported optimizations that do not involve a space-speed tradeoff are performed. Increases compilation time, but produces performance-enhanced code.
-o: Specify output file to be created
So here is an example command line: gcc -ansi -pedantic -Wall -O2 -o hello hello.c This produces an executable called hello in the directory where hello.c resides.
C Programming :: Introduction Summary
Program with understandability in mind. Speed in writing the program may pay off now, but writing a program with readability and understandability will pay off in the future.
Take advantage of the compiler's smarts! Use the "anal retentive" options!
Did I mention that you should make your programs well documented and understandable? :)
Note: From here on out, major topics will be highlighted in blue and subtopics will be highlighted in black.
C Programming :: Introduction
C is a simple programming language with few keywords and a relatively simple to understand syntax.
C is also useless. C itself has no input/output commands, doesn't have support for strings as a fundamental (atomic) data type. No useful math functions built in.
Because C is useless by itself, it requires the use of libraries. This increases the complexity of C. The issue of standard libraries is resolved through the use of ANSI libraries and other methods.
C Programming :: Hello, World
Let's give a go at a very simple program that prints out "Hello World" to standard out (usually your monitor). We'll call our little program hello.c. #include main() { printf("Hello, world!\n"); return 0; }
What?!?!? What's all this junk just to print out Hello, World? Let's see what's happening:
#include - Tells the compiler to include this header file for compilation.
What is a header file? They contain prototypes and other compiler/pre-processor directives. Prototypes are basic abstract function definitions. More on these later...
Some common header files are stdio.h, stdlib.h, unistd.h, math.h.
main() - This is a function, in particular the main block.
{ } - These curly braces are equivalent to stating "block begin" and "block end". These can be used at many places, such as if and switch.
printf() - Ah... the actual print statement. Thankfully we have the header file stdio.h! But what does it do? How is it defined?
return 0 - What's this? Who knows!
Seems like trying to figure all this out is just way too confusing. Let's break things up one at at time:
The return 0 statement. Seems like we are trying to give something back, and it is an integer. Maybe if we modified our main function definition: int main() Ok, now we are saying that our main function will be returning an integer! So remember, you should always explicitly declare the return type on the function!
Something is still a little fishy... I remember that 0 implied false... so isn't it returning that an int signifying a bad result? Thankfully there is a simple solution to this. Let's add #include to our includes. Let's change our return statement to return EXIT_SUCCESS;. Now it makes sense!
Let's take a look at printf. Hmm... I wonder what the prototype for printf is. Utilizing the man pages we see that printf is: int printf(const char *format, ...); printf returns an int. The man pages say that printf returns the number of characters printed. Now you wonder, who cares? Why should you care about this? It is good programming practice to ALWAYS check for return values. It will not only make your program more readable, but in the end it will make your programs less error prone. But in this particular case, we don't really need it. So we cast the function's return to (void). fprintf, fflush, and exit are the only functions where you should do this. More on this later when we get to I/O. For now, let's just void the return value.
What about documentation? We should probably doc some of our code so that other people can understand what we are doing. Comments in the C89 standard are noted by: /* */. The comment begins with /* and ends with */.
Let's see our new improved code! #include #include /* Main Function * Purpose: Controls our program, prints Hello, World! * Input: None * Output: Returns Exit Status */ int main() { (void)printf("Hello, world!\n"); return EXIT_SUCCESS; }
Much better! The KEY POINT of this whole introduction is to show you the fundamental difference between correctness and understandability. If you lose understandability in an attempt to gain correctness, you will lose in the end. Always place understandability as a priority ABOVE correctness. In the end, if a program is more understandable, the chances it can be fixed correctly will be much higher. You should always document your program. If you try to make your program itself more understandable, you stand less of a chance of screwing up your program later.
C Programming :: A Glimpse at Compilation
You will most likely be using the GNU C compiler, gcc. Most environments will have the cc variable set which is much more suitable when using Makefiles. A superficial look at compiling would entail: gcc file.c But is this what you really want? We get a file called a.out in our directory. This is because you aren't specifying the correct compiler options. Taking the theory of "that which is learned first is learned best", compile your programs using the "anal retentive" flags. This will not only catch more errors at compile time, but will help you create a program with less errors at run time. The recommended options to include while compiling are:
-ansi: Use ANSI C
-pedantic: Issue all warnings according to strict ANSI standard C
-Wall: Turn on all Warnings. ALWAYS use this. You will benefit from it.
-O2: Optimization Level 2, nearly all supported optimizations that do not involve a space-speed tradeoff are performed. Increases compilation time, but produces performance-enhanced code.
-o: Specify output file to be created
So here is an example command line: gcc -ansi -pedantic -Wall -O2 -o hello hello.c This produces an executable called hello in the directory where hello.c resides.
C Programming :: Introduction Summary
Program with understandability in mind. Speed in writing the program may pay off now, but writing a program with readability and understandability will pay off in the future.
Take advantage of the compiler's smarts! Use the "anal retentive" options!
Did I mention that you should make your programs well documented and understandable? :)
Note: From here on out, major topics will be highlighted in blue and subtopics will be highlighted in black.
C Programming :: Introduction
C is a simple programming language with few keywords and a relatively simple to understand syntax.
C is also useless. C itself has no input/output commands, doesn't have support for strings as a fundamental (atomic) data type. No useful math functions built in.
Because C is useless by itself, it requires the use of libraries. This increases the complexity of C. The issue of standard libraries is resolved through the use of ANSI libraries and other methods.
C Programming :: Hello, World
Let's give a go at a very simple program that prints out "Hello World" to standard out (usually your monitor). We'll call our little program hello.c. #include main() { printf("Hello, world!\n"); return 0; }
What?!?!? What's all this junk just to print out Hello, World? Let's see what's happening:
#include - Tells the compiler to include this header file for compilation.
What is a header file? They contain prototypes and other compiler/pre-processor directives. Prototypes are basic abstract function definitions. More on these later...
Some common header files are stdio.h, stdlib.h, unistd.h, math.h.
main() - This is a function, in particular the main block.
{ } - These curly braces are equivalent to stating "block begin" and "block end". These can be used at many places, such as if and switch.
printf() - Ah... the actual print statement. Thankfully we have the header file stdio.h! But what does it do? How is it defined?
return 0 - What's this? Who knows!
Seems like trying to figure all this out is just way too confusing. Let's break things up one at at time:
The return 0 statement. Seems like we are trying to give something back, and it is an integer. Maybe if we modified our main function definition: int main() Ok, now we are saying that our main function will be returning an integer! So remember, you should always explicitly declare the return type on the function!
Something is still a little fishy... I remember that 0 implied false... so isn't it returning that an int signifying a bad result? Thankfully there is a simple solution to this. Let's add #include to our includes. Let's change our return statement to return EXIT_SUCCESS;. Now it makes sense!
Let's take a look at printf. Hmm... I wonder what the prototype for printf is. Utilizing the man pages we see that printf is: int printf(const char *format, ...); printf returns an int. The man pages say that printf returns the number of characters printed. Now you wonder, who cares? Why should you care about this? It is good programming practice to ALWAYS check for return values. It will not only make your program more readable, but in the end it will make your programs less error prone. But in this particular case, we don't really need it. So we cast the function's return to (void). fprintf, fflush, and exit are the only functions where you should do this. More on this later when we get to I/O. For now, let's just void the return value.
What about documentation? We should probably doc some of our code so that other people can understand what we are doing. Comments in the C89 standard are noted by: /* */. The comment begins with /* and ends with */.
Let's see our new improved code! #include #include /* Main Function * Purpose: Controls our program, prints Hello, World! * Input: None * Output: Returns Exit Status */ int main() { (void)printf("Hello, world!\n"); return EXIT_SUCCESS; }
Much better! The KEY POINT of this whole introduction is to show you the fundamental difference between correctness and understandability. If you lose understandability in an attempt to gain correctness, you will lose in the end. Always place understandability as a priority ABOVE correctness. In the end, if a program is more understandable, the chances it can be fixed correctly will be much higher. You should always document your program. If you try to make your program itself more understandable, you stand less of a chance of screwing up your program later.
C Programming :: A Glimpse at Compilation
You will most likely be using the GNU C compiler, gcc. Most environments will have the cc variable set which is much more suitable when using Makefiles. A superficial look at compiling would entail: gcc file.c But is this what you really want? We get a file called a.out in our directory. This is because you aren't specifying the correct compiler options. Taking the theory of "that which is learned first is learned best", compile your programs using the "anal retentive" flags. This will not only catch more errors at compile time, but will help you create a program with less errors at run time. The recommended options to include while compiling are:
-ansi: Use ANSI C
-pedantic: Issue all warnings according to strict ANSI standard C
-Wall: Turn on all Warnings. ALWAYS use this. You will benefit from it.
-O2: Optimization Level 2, nearly all supported optimizations that do not involve a space-speed tradeoff are performed. Increases compilation time, but produces performance-enhanced code.
-o: Specify output file to be created
So here is an example command line: gcc -ansi -pedantic -Wall -O2 -o hello hello.c This produces an executable called hello in the directory where hello.c resides.
C Programming :: Introduction Summary
Program with understandability in mind. Speed in writing the program may pay off now, but writing a program with readability and understandability will pay off in the future.
Take advantage of the compiler's smarts! Use the "anal retentive" options!
Did I mention that you should make your programs well documented and understandable? :)
Note: From here on out, major topics will be highlighted in blue and subtopics will be highlighted in black.
v