THE C PREPROCESSOR

C allows for commands to the compiler to be included in the source code. These commands are then called preprocessor commands and are defined by the ANSI standard to be;
#if
#ifdef
#ifndef
#else
#elif
#include
#define
#undef
#line
#error
#pragma

 

All preprocessor commands start with a hash symbol, "#", and must be on a line on their own (although comments may follow).

#define

The #define command specifies an identifier and a string that the compiler will substitute every time it comes accross the identifier within that source code module. For example;

#define FALSE 0

#define TRUE !FALSE

The compiler will replace any subsequent occurence of 'FALSE' with '0' and any subsequent occurence of 'TRUE' with '!0'. The substitution does NOT take place if the compiler finds that the identifier is enclosed by quotation marks, so

printf ("TRUE");

would NOT be replaced, but

printf ("%d",FALSE);

would be.

The #define command also can be used to define macros that may include parameters. The parameters are best enclosed in parenthesis to ensure that correct substitution occurs.

This example declares a macro 'larger()' that accepts two parameters and returns the larger of the two;

#include <stdio.h>

#define larger(a,b) (a > b) ? (a) : (b)

int main()

{

printf ("\n%d is largest",larger(5,7));

}

#error

The #error command causes the compiler to stop compilation and to display the text following the #error command. For example;

#error REACHED MODULE B

will cause the compiler to stop compilation and display;

REACHED MODULE B

#include

The #include command tells the compiler to read the contents of another source file. The name of the source file must be enclosed either by quotes or by angular brackets thus;

#include "module2.c"

#include <stdio.h>

Generally, if the file name is enclosed in angular brackets, then the compiler will search for the file in a directory defined in the compiler's setup. Whereas if the file name is enclosed in quotes then the compiler will look for the file in the current directory.

#if, #else, #elif, #endif

The #if set of commands provide conditional compilation around the general form;

#if constant_expression

statements

#else

statements

#endif

#elif stands for '#else if' and follows the form;

#if expression

statements

#elif expression

statements

#endif

#ifdef, #ifndef

These two commands stand for '#if defined' and '#if not defined' respectively and follow the general form;

#ifdef macro_name

statements

#else

statements

#endif

#ifndef macro_name

statements

#else

statements

#endif

where 'macro_name' is an identifier declared by a #define statement.

#undef

Undefines a macro previously defined by #define.

#line

Changes the compiler declared global variables __LINE__ and __FILE __. The general form of #line is;

#line number "filename"

where number is inserted into the variable '__LINE__' and 'filename' is assigned to '__FILE __'.

#pragma

This command is used to give compiler specific commands to the compiler. The compiler's manual should give you full details of any valid options to go with the particular implementation of #pragma that it supports.

PROGRAM CONTROL STATEMENTS

As with any computer language, C includes statements that test the outcome of an expression. The outcome of the test is either TRUE or FALSE. The C language defines a value of TRUE as non-zero, and FALSE as zero.

Selection statements

The general purpose selection statement is "if" that follows the general form;

if (expression)

statement

else

statement

Where "statement" may be a single statement, or a code block enclosed in curly braces. The "else" is optional. If the result of the expression equates to TRUE, then the statement(s) following the if() will be evaluated. Otherwise the statement(s) following the else, if there is one, will be evaluated.

An alternative to the if....else combination is the ?: command that takes the form;

expression ? true_expression : false_expression

Where if the expression evaluates to TRUE, then the true_expression will be evaluated, otherwise the false_expression will be evaluated. Thus we get;

#include <stdio.h>

main()

{

int x;

x = 6;

printf ("\nx is an %s number", x % 2 == 0 ? "even" : "odd");

}

C also provides a multiple branch selection statement, switch , which successively tests a value of an expression against a list of values and branches program execution to the first match found. The general form of switch is;

switch (expression)

{

case value1 : statements

break ;

case value2 : statements

break ;

.

.

.

.

case valuen : statements

break ;

default : statements

}

The break statement is optional, but if omitted, program execution will continue down the list.

#include <stdio.h>

main()

{

int x;

x = 6;

switch (x)

{

case 0 : printf ("\nx equals zero");

break ;

case 1 : printf ("\nx equals one");

break ;

case 2 : printf ("\nx equals two");

break ;

case 3 : printf ("\nx equals three");

break ;

default : printf ("\nx is larger than three");

}

}

Switch statements may be nested within one another. This is a particularly useful feature for confusing people who read your source code!

Iteration statements

C provides three looping or iteration statements; for, while, and do-while. The for loop has the general form;

for(initialization;condition;increment)

and is useful for counters such as in this example that displays the entire ascii character set;

#include <stdio.h>

main()

{

int x;

for(x = 32; x < 128; x++)

printf ("%d\t%c\t",x,x);

}

An infinite for loop is also quite valid;

for(;;)

{

statements

}

Also, C allows empty statements. The following for loop removes leading spaces from a string;

for(; *str == ' '; str++)

;

Notice the lack of an initializer, and the empty statement following the loop.

The while loop is somewhat simpler than the for loop and follows the general form;

while (condition)

statements

The statement following the condition, or statements enclosed in curly braces will be executed until the condition is FALSE. If the condition is false before the loop commences, the loop statements will not be executed. The do-while loop on the other hand is always executed at least once. It takes the general form;

do

{

statements

}

while(condition);

Jump statements

The "return" statement is used to return from a function to the calling function. Depending upon the declared return data type of the function it may or may not return a value;

int MULT(int x, int y)

{

return(x * y);

}

or;

void FUNCA()

{

printf ("\nHello World");

return;

}

The "break " statement is used to break out of a loop or from a switch statement. In a loop it may be used to terminate the loop prematurely, as shown here;

#include <stdio.h>

main()

{

int x;

for(x = 0; x < 256; x++)

{

if (x == 100)

break ;

printf ("%d\t",x);

}

}

In contrast to "break " is "continue ", which forces the next iteration of the loop to occur, effectively forcing program control back to the loop statement.

C provides a function for terminating the program prematurely, "exit()". Exit() may be used with a return value to pass back to the calling program;

exit(return_value);

More About ?:

A powerful, but often misunderstood feature of the C programming language is ?:. This is an operator that acts upon a boolean expression, and returns one of two values dependant upon the result of the expression;

<boolean expression> ? <value for true> : <value for false>

It can be used almost anywhere, for example it was used in the binary search demonstration program;

printf ("\n%s\n",(result == 0) ? "Not found" : "Located okay");

Here it passes either "Not found" or "Located okay" to the printf () function dependant upon the outcome of the boolean expression 'result == 0'. Alternatively it can be used for assigning values to a variable;

x = (a == 0) ? (b) : (c);

Which will assign the value of b to variable x if a is equal to zero, otherwise it will assign the value of c to variable x.

This example returns the name of the executing program, without any path description;

#include <stdio.h>

#include <stddef.h>

#include <string.h>

char *progname(char *pathname)

{

/* Return name of running program */

unsigned l;

char *p;

char *q;

static char bnbuf[256];

return pathname? p = strrchr (pathname, '\\'),

q = strrchr (pathname, '.'),

l = (q == NULL? strchr (pathname, '\0'): q)

- (p == NULL? p = pathname: ++p),

strncpy (bnbuf, p, l),

bnbuf[l] = '\0',

strlwr (bnbuf)

: NULL;

}

void main(int argc, char *argv[])

{

printf ("\n%s",progname(argv[0]));

}

Continue

The continue keyword forces control to jump to the test statement of the innermost loop (while, do...while()). This can be useful for terminating a loop gracefuly as this program that reads strings from a file until there are no more illustrates;

#include <stdio.h>

void main()

{

FILE *fp;

char *p;

char buff[100];

fp = fopen("data.txt","r");

if (fp == NULL)

{

fprintf(stderr ,"Unable to open file data.txt");

exit(0);

}

do

{

p = fgets(buff,100,fp);

if (p == NULL)

/* Force exit from loop */

continue ;

puts(p);

}

while(p);

}

With a for() loop however, continue passes control back to the third parameter!

 

  Input/Output and Pointers.

 

Links:  Home C Programming Guide C++ programming Guide

Contact Me