Topic : Programming In C
Author : Brian Kernighan
Page : << Previous 11  Next >>
Go to page :


be  discussed
shortly,  lets  you  make  a  single  copy  of  the external
declarations for a program and then stick them into each  of
the source files making up the program.

23. #define, #include


     C provides a very limited macro facility.  You can say

     #define name            something

and thereafter anywhere ``name'' appears as a token, ``some-
thing'' will be substituted.  This is particularly useful in
parametering the sizes of arrays:

     #define ARRAYSIZE       100
             int     arr[ARRAYSIZE];
              ...
             while( i++ < ARRAYSIZE )...


(now we can alter the entire program by  changing  only  the
define) or in setting up mysterious constants:

     #define SET             01
     #define INTERRUPT       02      /* interrupt bit */
     #define ENABLED 04
      ...
     if( x & (SET | INTERRUPT | ENABLED) ) ...


Now we have meaningful  words  instead  of  mysterious  con-
stants.   (The  mysterious  operators `&' (AND) and `|' (OR)
will be covered in the  next  section.)  It's  an  excellent
practice  to  write  programs  without any literal constants
except in #define statements.

     There  are  several  warnings  about  #define.   First,
there's  no  semicolon at the end of a #define; all the text
from the name to the end of the line (except  for  comments)
is  taken  to  be the ``something''.  When it's put into the
text, blanks are placed around  it.   Good  style  typically
makes the name in the #define upper case _ this makes param-
eters more visible.  Definitions affect  things  only  after
they  occur,  and  only within the file in which they occur.
Defines can't be nested.  Last, if there is a #define  in  a
file, then the first character of the file MUST be a `#', to
signal the preprocessor that definitions exist.


     The other control word known  to  C  is  #include.   To
include one file in your source at compilation time, say

     #include "filename"

This is useful for putting a lot of heavily used data defin-
itions  and #define statements at the beginning of a file to
be compiled.  As with #define, the first line of a file con-
taining  a  #include  has to begin with a `#'.  And #include
can't be nested _ an included  file  can't  contain  another
#include.

24. Bit Operators


     C has several  operators  for  logical  bit-operations.
For example,

     x = x & 0177;

forms the bit-wise AND of x and 0177, effectively  retaining
only the last seven bits of x.  Other operators are

     |       inclusive OR
     ^       (circumflex) exclusive OR
     ~       (tilde) 1's complement
     !       logical NOT
     <<      left shift (as in x<<2)
     >>      right shift (arithmetic on PDP-11; logical on H6070, IBM360)


25. Assignment Operators


     An unusual feature of  C  is  that  the  normal  binary
operators  like  `+',  `-',  etc.   can be combined with the
assignment operator `=' to form  new  assignment  operators.
For example,

     x =- 10;

uses the assignment operator `=-' to decrement x by 10, and

     x =& 0177

forms the AND of x and 0177.  This convention  is  a  useful
notational  shortcut,  particularly  if  x  is a complicated
expression.  The classic example is summing an array:

     for( sum=i=0; i<n; i++ )
             sum =+ array[i];


But the  spaces  around  the  operator  are  critical!   For
     x = -10;

sets x to -10, while

     x =- 10;

subtracts 10 from x.  When no space is present,

     x=-10;

also decreases x by 10.   This  is  quite  contrary  to  the
experience  of  most  programmers.  In particular, watch out
for things like

     c=*s++;
     y=&x[0];


both of which are almost  certainly  not  what  you  wanted.
Newer  versions of various compilers are courteous enough to
warn you about the ambiguity.

     Because  all  other  operators  in  an  expression  are
evaluated  before  the  assignment  operator,  the  order of
evaluation should be watched carefully:

     x = x<<y | z;

means ``shift x left y places, then OR with z, and store  in
x.'' But

     x =<< y | z;

means ``shift x left by y|z places'', which is  rather  dif-
ferent.

26. Floating Point


     We've skipped over  floating  point  so  far,  and  the
treatment  here will be hasty.  C has single and double pre-
cision numbers (where the precision depends on  the  machine
at hand).  For example,

             double sum;
             float avg, y[10];
             sum = 0.0;
             for( i=0; i<n; i++ )
                     sum =+ y[i];
             avg = sum/n;


forms the sum and average of the array y.

     All floating arithmetic is done  in  double  precision.
Mixed mode arithmetic is legal; if an arithmetic operator in
an expression has both operands int or char, the  arithmetic
done  is  integer, but if one operand is int or char and the
other is float or double, both  operands  are  converted  to
double.  Thus if i and j are int and x is float,

     (x+i)/j         converts i and j to float
     x + i/j         does i/j integer, then converts

Type conversion may be made by assignment; for instance,

             int m, n;
             float x, y;
             m = x;
             y = n;


converts x to integer (truncating toward  zero),  and  n  to
floating point.

     Floating constants are just like those  in  Fortran  or
PL/I, except that the exponent letter is `e' instead of `E'.
Thus:

             pi = 3.14159;
             large = 1.23456789e10;


     printf will format floating point numbers: ``%w.df'' in
the format string will print the corresponding variable in a
field w digits wide, with d decimal places.  An e instead of
an f will produce exponential notation.

27. Horrors! goto's and labels


     C has a goto statement and labels, so  you  can  branch
about  the  way  you  used

Page : << Previous 11  Next >>