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
A field of digits beginning with a non-zero digit is a
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
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
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
- ^ 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.
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]