Data Conversions
#
Learning OutcomesAfter reading this section, you will be able to:
- How to convert between binary and hexadecimal notation
- How to convert between binary and decimal notation
#
IntroductionA C program at machine-level is an assembly language program. Assembly language uses hexadecimal representation for data. The hardware itself processes information in bits. When a program outputs data in hexadecimal or binary form, we may prefer to convert it into decimal form.
This chapter describes how to convert across binary, hexadecimal and decimal representations and shows what a trivially simple program looks like in binary and hexadecimal representations.
#
Binary - HexadecimalThe most convenient base for storing byte-wise information is hexadecimal (base 16). Two hexadecimal (base 16) digits can represent one byte of information. Each hexadecimal digit represents 4 bits of binary information.
For example, the hexadecimal value 0x5C is equivalent to the binary 010111002. The 0x prefix identifies the number as hexadecimal notation. The digits in the hexadecimal number system are {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, A, B, C, D, E, F}. The characters A through F denote decimal values 10 through 15 respectively.
#
Binary to HexadecimalTo convert a binary number to its hexadecimal equivalent, we:
- group the bits into nibbles,
- assign powers of 2 to the different bits in each nibble,
- multiply each bit value by the corresponding power of 2,
- add the products together for each nibble, and
- concatenate the nibble results
Consider the 8-bit number 010111002:
Nibble # | 1 | 0 | ||||||
Bit # | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 |
Multiplier | 8 | 4 | 2 | 1 | 8 | 4 | 2 | 1 |
Contents | 0 | 1 | 0 | 1 | 1 | 1 | 0 | 0 |
Nibble Values | 0*8 + 1*4 + 0*2 + 1*1 = 0x5 | 1*8 + 1*4 + 0*2 + 1*0 = 0xC | ||||||
Byte Value | 0x5C |
#
Hexadecimal to BinaryTo convert a hexadecimal number into its binary equivalent, we work from the lowest order bit to the highest. We identify the lowest order bit as the first target bit, then:
- divide by 2,
- put the remainder into the target bit,
- change the target to the next higher order bit
... and repeat the above until there are no more bits.
Consider the hexadecimal number 0x5C:
- Identify the first target bit as bit 0
- Divide the number (0x5C) into left and right hexadecimal digits
- Take the right digit (0xC), divide it by 2 and put the remainder (0) in bit 0
- Take the result (0x6), divide it by 2 and put the remainder (0) in bit 1
- Take the result (0x3), divide it by 2 and put the remainder (1) in bit 2
- Take the result (0x1), divide it by 2 and put the remainder (1) in bit 3
- Take the left hexadecimal digit (0x5), divide it by 2 and put the remainder (1) in bit 4
- Take the result (0x2), divide it by 2 and put the remainder (0) in bit 5
- Take the result (0x1), divide it by 2 and put the remainder (1) in bit 6
- Take the result (0x0), divide it by 2 and put the remainder (0) in bit 7
Bit# | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 |
Byte Value | 0x5C | |||||||
Nibble Values | 0x5 | 0xC | ||||||
Divide by 2 | 0 | 0 | 1 | 2 | 0 | 1 | 3 | 6 |
Bit Values | 0 | 1 | 0 | 1 | 1 | 1 | 0 | 0 |
#
Decimal - BinaryTo convert a non-negative integer into its binary equivalent, we start with the value and an empty container that consists of target bits. We take the integer value, identify the lowest order bit in the container as our target bit, and then:
- divide the value by 2,
- store the remainder in the target bit,
- take the result as the new integer value,
- identify the next higher-order bit our new target bit, and
- repeat this set of instructions until no value is left
Consider the value 92:
- Identify the target bit as bit numbered 0
- Take 92, divide it by 2 and put the remainder (0) in bit 0
- Take the result (46), divide it by 2 and store the remainder (0) in bit 1
- Take the result (23), divide it by 2 and store the remainder (1) in bit 2
- Take the result (11), divide it by 2 and store the remainder (1) in bit 3
- Take the result (5), divide it by 2 and store the remainder (1) in bit 4
- Take the result (2), divide it by 2 and store the remainder (0) in bit 5
- Take the result (1), divide it by 2 and store the remainder (1) in bit 6
- Take the result (0), divide it by 2 and store the remainder (0) in bit 7
Bit# | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 |
Value | 0 | 1 | 2 | 5 | 11 | 23 | 46 | 92 |
Bit Values | 0 | 1 | 0 | 1 | 1 | 1 | 0 | 0 |
(Eight bits and right to left bit numbering are for brevity and illustrative purposes only.)
To convert a binary number into its decimal equivalent, we multiply the value in each bit by its corresponding power of 2 and add the products together.
Consider the 8-bit binary number 010111002:
Bit # | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 |
Power of 2 | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 |
Bit Values | 0 | 1 | 0 | 1 | 1 | 1 | 0 | 0 |
Multiplier | 128 | 64 | 32 | 16 | 8 | 4 | 2 | 1 |
Byte Value | 0*128 + 1*64 + 0*32 + 1*16 + 1*8 + 1*4 + 0*2 + 0*1 = 92 |
#
Program Instructions (optional)A program instruction consists of an operation and possibly some operands. Each instruction performs an operation on its operands or on values stored in operand addresses. The addresses are either register names or addresses in primary memory.
The set of instructions in binary on a Windows 7 machine for a program that displays the phrase "This is C" looks like:
10110100 0000100110111010 00001001 0000000111001101 0010000111001101 0010000001010100011010000110100101110011001000000110100101110011001000000100001100100100
The equivalent hexadecimal representation is:
B409BA0901CD21CD2054686973206973204324
The first instruction moves the value 09 into register AH. 09 identifies the instruction that displays characters starting at the offset stored in register DX. The second instruction moves the offset value 0109 into register DX. The third instruction executes the instructions stored in register AH: displays the characters starting at offset 0109. The fourth instruction stops execution. The fifth through thirteenth lines hold the characters to be displayed. The fourteenth line holds the terminator that identifies the end of the set of characters.
The assembly language version of these instructions provides a more readable program. Assembly language consists of symbols and values that are more readable than simple hexadecimal digits. The assembly language version looks like:
MOV AH,09MOV DX,0109INT 21INT 20DB 'T'DB 'h'DB 'i'DB 's'DB ' 'DB 'i'DB 's'DB ' 'DB 'C'DB '$'
A Windows command line accepts assembly language instructions through the a
input option on the debug
program. Open a command prompt window and type the following:
debug-a1001456:0100 MOV AH,09 ;move code for displaying text into register AH 1456:0102 MOV DX,0109 ;move text address offset into register DX 1456:0105 INT 21 ;call the interrupt stored in register AH1456:0107 INT 20 ;stop execution1456:0109 DB 'T' ;text1456:010A DB 'h' ;...1456:010B DB 'i' ;to1456:010C DB 's' ;...1456:010D DB ' ' ;be1456:010E DB 'i' ;...1456:010F DB 's' ;displayed1456:0110 DB ' ' ;...1456:0111 DB 'C'1456:0112 DB '$' ;terminator character1456:0113-
a
refers to the input option to the debug
program. 100
identifies the offset in memory where the instructions start.
The first entry on each line is the memory address in segment:offset form. In debug
applications, the segments share the same address (0x14560
). The semi-colon refers to the end of a statement and the start of programmer comments.
To execute this program, we enter:
-gThis is C Program terminated normally-
To quit the debug program, we enter:
-q
The debug
program uses an operating system program called an assembler to convert our assembly language instructions into binary information as shown in the figure below:
We call the binary result machine language.