-1

I am trying to implement two bitwise functions in C:

set(unsigned *x, unsigned n, unsigned v) --> Sets the nth bit of the value x to the value v. V is either 0 or 1, and N is [0, 31] for simplicities sake.

flip(unsigned *x, unsigned n) --> Flips the Nth bit in x. Assume N is [0,31] for simplicities sake.

My implementation:


void set(unsigned *x, unsigned n, unsigned v) {
 
    *x = (1 << n) | v;
    
}


void flip(unsigned *x, unsigned n) {
    
    *x = n ^ (1 << *x);

}

My problem: The functions don't work logically.

The output from test cases:

Testing set_bit()

set_bit(0x0000004e,2,0) returned 0x00000004 but we expected 0x0000004a set_bit(0x0000006d,0,0) returned 0x00000001 but we expected 0x0000006c set_bit(0x0000004e,2,1) returned 0x00000005 but we expected 0x0000004e set_bit(0x0000006d,0,1) returned 0x00000001 but we expected 0x0000006d set_bit(0x0000004e,9,0) returned 0x00000200 but we expected 0x0000004e set_bit(0x0000006d,4,0) returned 0x00000010 but we expected 0x0000006d set_bit(0x0000004e,9,1) returned 0x00000201 but we expected 0x0000024e set_bit(0x0000006d,7,1) returned 0x00000081 but we expected 0x000000ed

Testing flip_bit()

flip_bit(0x0000004e,0) returned 0x00004000, but we expected 0x0000004f flip_bit(0x0000004e,1) returned 0x00004001, but we expected 0x0000004c flip_bit(0x0000004e,2) returned 0x00004002, but we expected 0x0000004a flip_bit(0x0000004e,5) returned 0x00004005, but we expected 0x0000006e flip_bit(0x0000004e,9) returned 0x00004009, but we expected 0x0000024e

  • 2
    For `set_bit`, don't you think the previous value of `*x` should appear somewhere on the right side of the assignment? Try some examples with paper and pencil. – Nate Eldredge Jul 01 '21 at 03:19
  • And `1 << *x` can't be right in `flip_bit`; `*x` isn't a bit index (and need not be in the range 0..31). – Nate Eldredge Jul 01 '21 at 03:20
  • The original version of this post specifically stated that loops and conditionals were not allowed. That condition has now apparently been removed. Don't do that. If you change your mind about what you want, that's a new, different question. Although loops don't help with this, conditionals do, and the best solutions will use them (either `if`/`else` or the conditional `?:` operator). It can be done without them of course, but it's not the best way to do it. – Tom Karzes Jul 01 '21 at 07:26
  • Does this answer your question? [How do you set, clear, and toggle a single bit?](https://stackoverflow.com/questions/47981/how-do-you-set-clear-and-toggle-a-single-bit) – Basya Jul 01 '21 at 08:57
  • In the question I linked to, note the section, "Changing the nth bit to x", in the accepted answer. – Basya Jul 01 '21 at 09:15

2 Answers2

2

You should give the variables more meaningful names than 1 character ones that has to be explained with comments.

We should never use signed numbers when doing bitwise operations and 1 is signed int. So 1<<31 is a bug.

Also, your function set cannot be used for setting a bit to value 0 since bitwise OR doesn't work that way. You either need separate functions for setting/clearing, or you need to include a branching if statement inside the function, example:

if(bit_value) 
  *value |= 1u<<n;
else
  *value &= ~(1u<<n);

A more sensible interface that can be used with any type, is to use an array of characters. Then you can pass along a pointer to integer, cast it, and it is guaranteed to work.

void bit_set (unsigned char* data, size_t byte, unsigned char bit)
{
  data[byte] |= 1u << bit;
}

void bit_clear (unsigned char* data, size_t byte, unsigned char bit)
{
  data[byte] &= ~(1u << bit);
}

void bit_toggle (unsigned char* data, size_t byte, unsigned char bit)
{
  data[byte] ^= 1u << bit; 
}
Lundin
  • 195,001
  • 40
  • 254
  • 396
1

If we logically follow through with your code, we can see what is happening. Let's use your first example with input 0x4e and output 0x04. I'm only going to look at one byte for simplicity's sake.

First, you bitshift 1 over N amount of times. In this case, N = 2. In binary, that looks like this:

value    : N
---------:--
00000001 : 0
00000010 : 1
00000100 : 2

next, we bitwise-or that value with V where V = 0:

00000100 | 00000000 => 00000100

and last, that value gets assigned to the value at the address X. In binary, the value 00000100 is equivalent to 0x04 in hexadecimal which matches your actual output.

Now that we have identified the logical error, we can propose appropriate instructions to get you where you want to be. I propose the following (though there may be other ways that are better).

void set_bit(unsigned *x, unsigned n, unsigned v) {
 
    unsigned temp = (1 << n);
    *x = v ? *x | temp : *x & ~temp;
    
}

What is happening here is first we are storing the value calculated by the bitshift: 00000100. Then we are choosing to do one of two instructions based on the value of V.

if v == 1
    X        : TEMP                 : HEX
    01001110 | 00000100 => 01001110 : 0x4e
if v == 0
    X        : ~TEMP                 : HEX
    01001110 & 11111011 => 01001010 : 0x4a

This should get you to your desired output when V = 0.

The other function is actually much simpler. We can do a bitwise-exclusive-or:

void flip_bit(unsigned *x, unsigned n) {
    
    unsigned temp = (1 << n);
    *x ^= temp;

}

And this is how it looks in binary when N = 0:

X        : TEMP                 : HEX
01001110 ^ 00000001 => 01001111 : 0x4f

Again, that matches your expected output.

If any of this is confusing, a simple google search of how bitwise operators work should provide insight.

Dharman
  • 30,962
  • 25
  • 85
  • 135
pa-mims
  • 41
  • 4