Lab 3: Bits of Trouble
Due by the end of class
Introduction
In this lab you will be exploring some bitwise operations in C. To do so, you must write a program that that takes numerical input.
Here is an example program that creates a readInt()
function to read an int
value from standard input, one character at a time. Because this function is used by the main()
function, it should be written before the body of main()
. Java did not have this restriction and allowed methods to be written in any order.
When we discuss functions in the future, we will cover a technique called prototyping that eliminates the need to define a function before it's used. For now, it's simpler to put the function first.
#include <stdio.h> /** * Function: readInt * Returns: an int, read from standard input. **/ int readInt () { int c = 0; int i = 0; while ((c = getchar ()) != EOF && c != '\n') { if (c >= '0' && c <= '9') i = i * 10 + (c - '0'); } return i; } int main () { int value = 0; printf ("Please enter a numerical value: "); value = readInt (); printf ("Your value is %d.\n", value); return 0; }
Your Mission
Create an executable program called bits
which reads an integer value from the user, using the readInt()
function defined above. Then, ask the user if he or she wants to set, unset, or flip a bit inside this number. No matter which of the three options the user selects, you will need to read in another integer (in the range 0 to 31) to determine which bit to change. Finally, print out the number after the single bit change has happened.
As you can see above, the code that reads in an int
value is not complex. It takes in character values representing digits, subtracts the value '0'
from them to bring them into the range 0-9, and adds them to a running sum. It continues until it reaches a newline ('\n'
) or the end of the file, and it ignores all other characters. It does not have robust error checking. In your program, you must use getchar()
to read in the letter corresponding to setting, unsetting, or flipping a bit. However, the user will hit enter after that letter, producing a newline in the input. If you don't ignore that newline (by reading it in separately), the next call to readInt()
will return 0
, since it will immediately hit the newline.
Below is more information about the three operations.
Setting a Bit
For this program, the possible bits we can affect are numbered 0 (for the least significant bit, also known as the 1's place) up to 31 (for the most significant bit, perhaps the 2,147,483,648's place, but it won't be considered that since we're dealing with signed int
values).
Setting a bit changes it to a 1 if it is a 0. If the bit is already a 1, then setting the bit should have no effect. So, how can you set a bit? Well, if you could take a single bit and shift it to the correct location, then you can use a bitwise OR
to combine it with another number. Since the OR
will make that bit a 1 if either of the bits being combined is a 1 (and you've shifted a 1 to the right place), it should work.
But where do you get a single 1 bit from? Well, the place most people start is the integer 1
. It consists of 31 0 bits followed by a single 1 bit. If you can shift that single bit into the right place, you're good to go. Otherwise, it's hard to get your hands on individual bits. Using a known pattern of bits (in this case just a single 1 bit) to interact with bits in another number is called masking.
Unsetting a Bit
The idea here is similar to setting a bit, except that we want to make the specified bit 0. If the bit is already 0, unsetting it has no effect. If there was only some way to get a mask that was all 1 bits except for the location you want (which would be a 0 bit), then you could bitwise AND
it with the number whose bit your are trying to unset.
As before, you'll start with a the integer 1
and shift it where it needs to go. Then, you'll have a mask that's all 0 bits except for a 1 bit at the location of interest. A bitwise negation will turn it into all 1 bits with a 0 bit at the location of interest. And that's that.
Flipping a Bit
Again, the idea here is similar to setting a bit, except that we want to change the bit. If the bit is 0, it should become a 1. If the bit is 1, it should become a 0.
Produce a mask in exactly the same way that you did for setting a bit. However, instead of using a bitwise OR
, use a bitwise XOR
. In that way, a 0 bit XOR
a 1 bit will result in a 1 bit, but a 1 bit XOR
a 1 bit will result in a 0 bit.
Sample Execution
Below is sample output for three separate executions of the program. In each case, the user enters 500
for the integer. In the first example, the user chooses to set bit 3. User input is shown in green
.
Enter an integer: 500 Do you want to set, unset, or flip a bit? (s, u, f): s Which bit? (0-31): 3 The result of setting bit 3 in 500 is 508
In the next example, the user chooses to unset bit 2.
Enter an integer: 500 Do you want to set, unset, or flip a bit? (s, u, f): u Which bit? (0-31): 2 The result of unsetting bit 2 in 500 is 496
In the last example, the user chooses to flip bit 4.
Enter an integer: 500 Do you want to set, unset, or flip a bit? (s, u, f): f Which bit? (0-31): 4 The result of flipping bit 4 in 500 is 484
Turn In
Zip the contents of your lab directory, including the makefile and the source C file. Upload this zip file to Brightspace. Do not include any object files or executables. Running the make
command must compile the required C source code file and generate an executable named bits
.
All work must be done individually. Never look at someone else's code. Please refer to the course policies if you have any questions about academic integrity. If you have trouble with the assignment, I am always available for assistance.