#include #include /*************************************************** * Finding bugs in bit masks * * Recall that the individual bits of an integer can * be used as Boolean-valued flags. * * For example, four bits can represent four * independent Boolean values: * * bit: 3 2 1 0 * * flags: 0 0 0 0 * * Each bit can independently be either 0 or 1. * * Suppose we want four masks, one for each flag. * Three different sets of masks are given below: * * masks_a = { 0, 1, 2, 4 } * masks_b = { 1, 2, 3, 4 } * masks_c = { 1, 2, 4, 8 } * * Which set correctly represents four independent * flags? * * What is wrong with the other two sets? * * Run the program and experiment with turning the * four flags on and off. * * * WHAT SHOULD A MASK LOOK LIKE? * * A mask representing one Boolean flag must contain * exactly one 1 bit. * * For four independent flags, the masks should be * * decimal binary * * 1 0001 * 2 0010 * 4 0100 * 8 1000. * * Each mask selects exactly one different bit. * * * TURNING A FLAG ON * * To turn on the flag represented by mask, use * * flags |= mask; * * The 1 bit in mask sets the corresponding bit in * flags while leaving all other bits unchanged. * * * TURNING A FLAG OFF * * To turn off the flag represented by mask, use * * flags &= ~mask; * * Complementing mask places a 0 in the position we * want to clear and 1s everywhere else. * * * TESTING A FLAG * * To determine whether a flag is set, use * * (flags & mask) != 0. * * If the selected bit is 1, the result is nonzero. * If the selected bit is 0, the result is zero. ***************************************************/ // Function declarations int main(); void print_flags( std::uint32_t flags, const std::uint32_t masks[] ); // Function definitions int main() { std::uint32_t masks_a[4]{ 0, 1, 2, 4 }; std::uint32_t masks_b[4]{ 1, 2, 3, 4 }; std::uint32_t masks_c[4]{ 1, 2, 4, 8 }; std::uint32_t flags_a{ 0 }; std::uint32_t flags_b{ 0 }; std::uint32_t flags_c{ 0 }; while ( true ) { int flag{}; std::cout << "Enter a flag (0-3) and anything else to quit: "; std::cin >> flag; if ( !std::cin || (flag < 0) || (flag > 3) ) { break; } bool turn_on{}; std::cout << "Turn it on (1) or turn it off (0)? "; std::cin >> turn_on; if ( !std::cin ) { break; } if ( turn_on ) { flags_a |= masks_a[flag]; flags_b |= masks_b[flag]; flags_c |= masks_c[flag]; } else { flags_a &= ~masks_a[flag]; flags_b &= ~masks_b[flag]; flags_c &= ~masks_c[flag]; } std::cout << "a: "; print_flags( flags_a, masks_a ); std::cout << "b: "; print_flags( flags_b, masks_b ); std::cout << "c: "; print_flags( flags_c, masks_c ); std::cout << std::endl; } return 0; } /*************************************************** * print_flags * * Print '*' if the corresponding flag is set and * 'o' if it is not set. ***************************************************/ void print_flags( std::uint32_t flags, const std::uint32_t masks[] ) { for ( unsigned int k{ 0 }; k < 4; ++k ) { if ( (flags & masks[k]) != 0 ) { std::cout << "*"; } else { std::cout << "o"; } } std::cout << std::endl; } // Explanation: // // Only masks_c correctly represents four independent // Boolean flags: // // masks_c[0] = 1 = 0001 // masks_c[1] = 2 = 0010 // masks_c[2] = 4 = 0100 // masks_c[3] = 8 = 1000. // // Each mask contains exactly one 1 bit, and each 1 // appears in a different position. // // // What is wrong with masks_a? // // masks_a = { 0, 1, 2, 4 } // // The first mask is // // 0000. // // It does not select any bit. Consequently, // // flags |= 0 // // cannot turn anything on, and // // flags &= ~0 // // cannot turn anything off. // // Thus, the first "flag" does not exist. // // // What is wrong with masks_b? // // masks_b = { 1, 2, 3, 4 } // // In binary, these are // // 0001 // 0010 // 0011 // 0100. // // The mask // // 3 = 0011 // // contains two 1 bits. It therefore does not // represent an independent Boolean flag. // // Turning on this "flag" using // // flags |= 3; // // sets both bits 0 and 1. // // Similarly, clearing this "flag" using // // flags &= ~3; // // clears both bits 0 and 1. // // Thus, the supposed third flag overlaps the first // two flags. // // // There was also a bug in the original print_flags // function. It tested // // (flags & masks[k]) == flags. // // This does not ask whether the selected flag is set. // It asks whether masking flags leaves the entire // value of flags unchanged. // // The appropriate test is // // (flags & masks[k]) != 0. // // This asks directly whether the bit selected by the // mask is 1.