0

I have a particular byte where each bit in the byte depends on some other value or information. In particular, one byte is formatted as follows:

Bits 1-3 = 011
Bits 4-7 = binary value of char at that position
Bit 8 = 1 or 0 depending on a 2nd parameter

Thus, I thought I might replace code like:

  if (last == TRUE) {
     callsign[j] = 0b01100001;
  } else {
     callsign[j] = 0b01100000;
  }

with the simple two-liner:

  char mask[];
  sprintf("%s%i", 0b1111111, last); 
  callsign[j] = 0b01100001 & mask;

Unfortunately, that didn't work, generating a ton of errors, among them an Attempt to create a pointer to a constant, which I can't decipher.

Essentially, either way, I need to create a byte composed of individual bits or groups of bits in a specific order. Inevitably, they will be variables, and somehow I need to concatenate them into a byte.

I was thinking masks would be the way to go, but even if I opt for a mask, I somehow need to concatenate a parameter into the mask.

What's the best way to go about this? Using masks seems convenient, but how can I create a mask by combining variables with binary?

InterLinked
  • 1,247
  • 2
  • 18
  • 50
  • 2
    You're completely misusing `sprintf`. – Thomas Jager Aug 01 '19 at 15:04
  • @ThomasJager Oops, `int mask; sprintf(mask, "%s%i", 0b1111111, last);`, but would that get me a working mask? – InterLinked Aug 01 '19 at 15:07
  • 1
    You don't need sprintf to do bit masking. I don't know why you think you do. It greatly complicates things. – Robert Harvey Aug 01 '19 at 15:07
  • @RobertHarvey How do you recommend going about this? – InterLinked Aug 01 '19 at 15:08
  • @InterLinked Now you're using an uninitialized `int` as a `char *`, twice. That's still completely wrong. The first is the string being written to, the second is the `"%s"` format specifier. – Thomas Jager Aug 01 '19 at 15:09
  • @ThomasJager OK, `char mask[]; sprintf(mask, "%s%i", 0b1111111, last);` then, but then I am combining a binary value with a char mask – InterLinked Aug 01 '19 at 15:10
  • 1
    By doing your bit masking the usual way. ` 0b01100001 & 0b01100000` masks off bits 2 and 3. Well, what you're calling bits 2 and 3. They're actually bits 5 and 6 (bits are counted from right to left, starting at zero). – Robert Harvey Aug 01 '19 at 15:13
  • 4
    @InterLinked `0b11111111` is an integer. I don't know why you think that `sprintf` is the right tool for this. There are many problems in with your question. You've got the order of the bits wrong (They go 7-0, not 1-8). Using `sprintf` has **way** more overhead than just using the if. It's also not clear what your actual problem is. You mention bits 4-7, but then never show any code that touches them. – Thomas Jager Aug 01 '19 at 15:13
  • @ThomasJager I can do the if, but the problem is I have another scenario as listed where I have multiple inputs forming the byte, way too much to do an if/elseif/elseif.../else type deal. If I can't get this working, I don't see how I would even approach that. – InterLinked Aug 01 '19 at 15:15
  • 2
    I'm still trying to figure out what you want to do here. Do you just want to extract bits? Then masking/shifting is the answer. – yhyrcanus Aug 01 '19 at 15:15
  • @yhyrcanus No, I need to do the opposite, set bits, The first 3 bits are always 011. The remaining 5 are a tossup each time, which is why subbing variables in somehow for those bit values is ideal – InterLinked Aug 01 '19 at 15:15
  • 1
    https://stackoverflow.com/questions/47981/how-do-you-set-clear-and-toggle-a-single-bit – Robert Harvey Aug 01 '19 at 15:16
  • @InterLinked I'd recommend finding a good book/resource on C. The operators include bit-shifting, to align the bits you want to use in the right place, bitwise-and to mask out bits, and bitwise-or to combine sets of bits. You *need* to understand these to effectively do what you want. – Thomas Jager Aug 01 '19 at 15:17
  • @RobertHarvey That helps, but in addition to setting the last bit, I also need to set bits 4-7 at once – InterLinked Aug 01 '19 at 15:17
  • 1
    https://stackoverflow.com/questions/21786843/how-to-set-multiple-bits-in-one-line-in-c – Robert Harvey Aug 01 '19 at 15:18
  • I think all you really want to do is `((3)<<6)|((char&0xF)<<1)|(bit&1)` . 3 is a constant, char&0xF is the lower nibble of the character ( bits "4-7" through your convention), and bit is that extra boolean at the end. – yhyrcanus Aug 01 '19 at 15:22
  • @yhyrcanus Best not to use `char`, even if it's as an example, because it's a reserved keyword. – Thomas Jager Aug 01 '19 at 15:24
  • @yhyrcanus Oops, I meant 4-7 on a 1-8 scale, bits 3-6 starting from 0. So 1 bit from the higher nibble and 3 from the lower. – InterLinked Aug 01 '19 at 15:24
  • @RobertHarvey That second link ultimately helped me figure out what needed to be done, thanks! – InterLinked Aug 01 '19 at 15:52

1 Answers1

1

You can toggle bits using the "or" | and "and" & operator.

uint8_t some_byte = 0b10000000;
some_byte |= 0b00100000;
// Result:   0b10100000.

some_byte  = 0b10000011;
some_byte &= 0b01111111;
// Result:   0b00000011.
earthling
  • 620
  • 6
  • 20
  • I was going down this route, I just added `int cs = 0b01100001 | last;` which should give 01100000 if last is 0 and 01100001 if true. But then I need to set the 4 0s in the middle to the binary representation of callsign[j], how do you recommend that? – InterLinked Aug 01 '19 at 15:28
  • No, 0bxxxxxxxx | 0 is still 0bxxxxxxxx. 0bxxxxxxxx & 0 will result in 0. Use &= to set bit to zero and |= to set it to one. 0bxxxxxxxx & 0b11000011 -> 0bxx0000xx 0bxxxxxxxx | 0b11000011 -> 0b11xxxx11 – earthling Aug 01 '19 at 15:32
  • I don't see how that differs. The variable `last` in my snippet could be either 0 or 1 depending on what arg was passed in – InterLinked Aug 01 '19 at 15:34
  • 1
    If the 4 zeros are always zeros, and callsign[j] has a max of 4 used bits (0b0000xxxx), shift callsign[j] one to the left and add it to 0b0110000x. `int cs = (0b01100000 | last) + (callsign[j] << 1);` I would suggest using an unsigned int for this kind of operation. – earthling Aug 02 '19 at 05:57
  • Thanks - I did get it to work, and that's more or less what I ended up doing. Not in an elegant one liner, but in two lines, if I remember correctly. – InterLinked Aug 03 '19 at 11:31