# CSCD-2552015-02-05

## Octal, Hexadecimal and Binary Numbers and Bitwise Operations

Tom Lehrer's "New Math" — introduction to octal arithmetic.  Note:  C was initially developed on a PDP-11 computer, which used octal numbers to report bit patterns.

C's rules for representing decimal, octal, and hexadecimal numbers in constants.
A field of digits beginning with a non-zero digit is a decimal number
A field beginning with "0x" is a hexadecimal number.  The following characters are 0-9 and a-f .  "0X" and A-F are also allowed.
Otherwise a field beginning with 0 is an octal number.  The following characters are 0-7.

Connection between octal numbers, hexadecimal numbers and binary numbers:
In an octal number, each digit represents three bits in the binary number, 0 for "000" up through 7 for "111".
In a hexadecimal number, each digit represents four bits in the binary number, 0 for "0000" up through F for "1111".  The digits are referred to as nibbles — 2 nibbles to a byte.

In a binary number, the bits are numbered from zero (the least significant bit) to (size-1), the most significant bit.  This is also the sign bit for an integer (unless it has been expressly declared as unsigned).

Drill program on conversion of decimal numbers to binary, octal, and hexadecimal.  Reports the octal and hex and pauses before showing the binary.
binary_out.txt   binary_out.c   binary_out.exe

There is a unary binary operator, the ~.  It has the same precedence and associativity as the other unary operators (just under parentheses and square brackets).  Its effect is to invert every bit in its operand.

There are two bitwise shift operators, where the left operand is the number being modified and the right operand is the size of the shift.  Their precedence is below arithmetic operators and above comparison operators.

• << is the left-shift operator.  num << k will shift to the left the bits in num by k positions.  Zeros come in at the least significant bit and fall off after the most significant bit.  The operation is equivalent to multiplying by a power of two.  So  num << 2 is the equivalent of num * 4.
• >> is the right-shift operator.  num >> k will shift to the right the bits in num by k positions.  The operation is equivalent to dividing by a power of 2.  Bits fall off the least significant bit.  The behavior at the most significant bit depends on what kind of a number is in num.  If it is a signed number, then negative numbers need to remain negative numbers.  So the sign bit is copied to the positions below it.  If it is an unsigned number, the most significant bit is just another numeric bit and zeros come into that position.

The other bitwise operators have precedence between the comparison operators (< > etc.) and the boolean/logical operators (&& and ||).  They require integers operands.  Typically one operand is the number being examined and the other operand is a "mask", a bit pattern for modifying that number.  In order of descending precedence the bitwise operators are:

• & the bitwise AND.  The AND operation is performed between every bit in the two operands.  As with the boolean operators, this is considered as a bitwise multiply.  A common use is to examine individual bits in a number by using the appropriate mask.  For instance, 0x10 (in binary, 00010000) will be non-zero only if bit 4 contains a 1.  All other positions are zeros, which turn off bits.  If you are testing whether a number is even or odd, (num & 1) leaves only the least significant bit.  If that is 1 the number is odd, if it is 0 the number is even.
• ^ the exclusive or operator (abbreviated as XOR for documentation purposes).  Taking the XOR of two bits returns a 0 if they are the same (0 ^ 0 and 1 ^ 1) and returns a 1 if they are different (0 ^ 1 and 1 ^ 0).  This can be used to invert a bit in a number by using the appropriate mask.  For instance, 0x10 (in binary, 00010000) will invert bit 4 (0 ^ 1 is 1 and 1 ^ 1 is 0).  All other positions are unaltered, since (0 ^ 0 is 0 and and 1 ^ 0 is 1).
• | the inclusive OR.  At the bitwise level, this is the same as the boolean OR (||):  the result is a 1 unless both bits are zero.  This can be used to force a bit to 1 by using the appropriate mask.  For instance,  0x10 (in binary, 00010000) will turn on bit 4 regardless of what it contains and will leave the other bits unchanged (0 | 0 is 0 and 1 | 0 is 1).

Students who go on to the Operating Systems course will see a lot more of this stuff.

Enrichment Material

Conversion of user input with scanf

• %i will accept any integer value, using C's rules for decimal, octal, and hexadecimal numbers.
• %d will treat the number as a decimal number.  So a leading zero is ignored.
• %o will treat the number as an octal number.  The leading zero is not required since only octal numbers are accepted..
• %x  treat the number as an octal number.  The leading "0x" is not required since only hexadecimal numbers are accepted.

Output of octal and hexadecimal numbers with printf:  the bare %o and %x print the number without the leading zero or "0x".
To force that output,. one must use the specification %#o and %#x — the "#" flag specifies that 'the value should be converted to an "alternate form"'. [Linux man page on fprintf]