home *** CD-ROM | disk | FTP | other *** search
- .NH
- Bit Operators
- .PP
- C has several operators for logical bit-operations.
- For example,
- .E1
- x = x & 0177;
- .E2
- forms the bit-wise
- .UC AND
- of
- .UL x
- and 0177,
- effectively retaining only the last seven bits of
- .UL x\*.
- Other operators are
- .E1
- .ft R
- \(or inclusive OR
- ^ (circumflex) exclusive OR
- .tr+~
- + (tilde) 1's complement
- .tr++
- ! logical NOT
- << left shift (as in x<<2)
- >> right shift (arithmetic on PDP\(hy11; logical on H6070, IBM360)
- .E2
- .NH
- Assignment Operators
- .PP
- An unusual feature of C
- is that the normal binary operators like
- `+', `\(mi', etc.
- can be combined with the assignment operator `='
- to form new assignment operators.
- For example,
- .E1
- x =- 10;
- .E2
- uses the assignment operator `=\(mi' to decrement
- .UL x
- by 10,
- and
- .E1
- x =& 0177
- .E2
- forms the
- .UC AND
- of
- .UL x
- and 0177.
- This convention is a useful notational shortcut,
- particularly if
- .UL x
- is a complicated expression.
- The classic example is summing an array:
- .E1
- for( sum=i=0; i<n; i\*+ )
- sum =+ array[i];
- .E2
- But the spaces around the operator are critical!
- For instance,
- .E1
- x = -10;
- .E2
- sets
- .UL x
- to
- \(mi10, while
- .E1
- x =- 10;
- .E2
- subtracts 10 from
- .UL x\*.
- When no space is present,
- .E1
- x=-10;
- .E2
- also decreases
- .UL x
- by 10.
- This is quite contrary to the experience of most programmers.
- In particular, watch out for things like
- .E1
- c=\**s\*+;
- y=&x[0];
- .E2
- both of which are almost certainly not what you wanted.
- Newer versions of various compilers are courteous enough to warn you about the ambiguity.
- .PP
- Because all other operators in an expression are evaluated
- before the assignment operator,
- the order of evaluation should be watched carefully:
- .E1
- x = x<<y | z;
- .E2
- means
- ``shift
- .UL x
- left
- .UL y
- places,
- then
- .UC OR
- with
- .UL z,
- and store in
- .UL x\*.''
- But
- .E1
- x =<< y | z;
- .E2
- means
- ``shift
- .UL x
- left by
- .UL y|z
- places'',
- which is rather different.
- .NH
- Floating Point
- .PP
- We've skipped over floating point so far,
- and the treatment here will be hasty.
- C has single and double precision numbers
- (where the precision depends on the machine at hand).
- For example,
- .E1
- double sum;
- float avg, y[10];
- sum = 0\*.0;
- for( i=0; i<n; i\*+ )
- sum =+ y[i];
- avg = sum/n;
- .E2
- forms the sum and average of the array
- .UL y\*.
- .PP
- All floating arithmetic is done in double precision.
- Mixed mode arithmetic is legal;
- if an arithmetic operator in an expression
- has both operands
- .UL int
- or
- .UL char,
- the arithmetic done is integer, but
- if one operand is
- .UL int
- or
- .UL char
- and the other is
- .UL float
- or
- .UL double,
- both operands are converted to
- .UL double\*.
- Thus if
- .UL i
- and
- .UL j
- are
- .UL int
- and
- .UL x
- is
- .UL float,
- .E1
- (x+i)/j converts i and j to float
- x + i/j does i/j integer, then converts
- .E2
- Type conversion
- may be made by assignment;
- for instance,
- .E1
- int m, n;
- float x, y;
- m = x;
- y = n;
- .E2
- converts
- .UL x
- to integer
- (truncating toward zero),
- and
- .UL n
- to floating point.
- .PP
- Floating constants are just like those in Fortran or PL/I,
- except that the exponent letter is `e' instead of `E'.
- Thus:
- .E1
- pi = 3\*.14159;
- large = 1\*.23456789e10;
- .E2
- .PP
- .UL printf
- will format floating point numbers:
- .UL ``%w\*.df''
- in the format string will print the corresponding variable
- in a field
- .UL w
- digits wide, with
- .UL d
- decimal places.
- An
- .UL e
- instead of an
- .UL f
- will produce exponential notation.
- .NH
- Horrors! goto's and labels
- .PP
- C has
- a
- .UL goto
- statement and labels, so you can branch about
- the way you used to.
- But most of the time
- .UL goto's
- aren't needed.
- (How many have we used up to this point?)
- The code can almost always be more clearly expressed by
- .UL for/while,
- .UL if/else,
- and compound statements.
- .PP
- One use of
- .UL goto's
- with some legitimacy is in a program
- which
- contains a long loop,
- where a
- .UL while(1)
- would be too extended.
- Then you might write
- .E1
- mainloop:
- \*.\*.\*.
- goto mainloop;
- .E2
- Another use is to implement a
- .UL break
- out of more than one level of
- .UL for
- or
- .UL while\*.
- .UL goto's
- can only branch to labels within the same function.
- .NH
- Acknowledgements
- .PP
- I am indebted to a veritable host of readers who made
- valuable criticisms on several drafts of this tutorial.
- They ranged in experience from complete beginners
- through several implementors of C compilers
- to the C language designer himself.
- Needless to say, this is a wide enough spectrum of opinion
- that no one is satisfied (including me);
- comments and suggestions are still welcome,
- so that some future version might be improved.
-