5

I am trying to create a bitmaped data in , here is the code I used but I am not able to figure the right logic. Here's my code

bool a=1;
bool b=0;
bool c=1;
bool d=0;

uint8_t output = a|b|c|d;

printf("outupt = %X", output);

I want my output to be "1010" which is equivalent to hex "0x0A". How do I do it ??

Lundin
  • 195,001
  • 40
  • 254
  • 396
KBh
  • 53
  • 2
  • 1
    output should be 1. I mean you have 1 | 0 | 1 | 0 which is 1. – drescherjm Sep 13 '20 at 21:16
  • Do you know about the bitwise *shift* opreators `<<` and `>>`? Perhaps you should consider a [decent book or two](https://stackoverflow.com/a/388282/440558)? – Some programmer dude Sep 13 '20 at 21:17
  • @Scheff While that is true, we do not remove the C++ tag when there are C++ answers present, because that might render those answers bad and off-topic. Please see the tag usage guidlines in C and C++ tag wikis. I did a rollback. – Lundin Sep 14 '20 at 06:31
  • @Scheff People who write answers don't always check the question carefully - they might follow either only the C or only the C++ tag and then assume the question is in that language. So they write an answer in good faith. If we remove the C++ tag, then those answers come across as off-topic and may attract down votes for that reason alone. – Lundin Sep 14 '20 at 06:59
  • 1
    @Scheff You have to click on the "learn more" option in top of those links. (Thanks to recent UI changes, it is now even harder to find than before...) Here is the [C tag wiki](https://stackoverflow.com/tags/c/info) and [C++ tag wiki](https://stackoverflow.com/tags/c%2b%2b/info). – Lundin Sep 14 '20 at 08:04

3 Answers3

7

The bitwise or operator ors the bits in each position. The result of a|b|c|d will be 1 because you're bitwise oring 0 and 1 in the least significant position.

You can shift (<<) the bits to the correct positions like this:

uint8_t output = a << 3 | b << 2 | c << 1 | d;

This will result in

    00001000 (a << 3)
    00000000 (b << 2)
    00000010 (c << 1)
  | 00000000 (d; d << 0)
    --------
    00001010 (output)

Strictly speaking, the calculation happens with ints and the intermediate results have more leading zeroes, but in this case we do not need to care about that.

0

If you're interested in setting/clearing/accessing very simply specific bits, you could consider std::bitset:

bitset<8> s;   // bit set of 8 bits

s[3]=a;        // access individual bits, as if it was an array
s[2]=b;
s[1]=c; 
s[0]=d;        // the first bit is the least significant bit

cout << s <<endl;       // streams the bitset as a string of '0' and '1' 
cout << "0x"<< hex << s.to_ulong()<<endl;    // convert the bitset to unsigned long
cout << s[3] <<endl;     // access a specific bit
cout << "Number of bits set: " << s.count()<<endl; 

Online demo

The advantage is that the code is easier to read and maintain, especially if you're modifying bitmapped data. Because setting specific bits using binary arithmetics with a combination of << and | operators as explained by Anttii is a vorkable solution. But clearing specific bits in an existing bitmap, by combining the use of << and ~ (to create a bit mask) with & is a little more tricky.

Another advantage is that you can easily manage large bitsets of hundreds of bits, much larger than the largest built-in type unsigned long long (although doing so will not allow you to convert as easily to an unsigned long or an unsigned long long: you'll have to go via a string).

Christophe
  • 68,716
  • 7
  • 72
  • 138
-1

C only

I would use bitfields. I know that they are not portable, but for the particular embedded hardware (especially uCs) it is well defined.

#include <string.h>
#include <stdio.h>
#include <stdbool.h>


typedef union 
{
    struct 
    {
        bool a:1;
        bool b:1;
        bool c:1;
        bool d:1;
        bool e:1;
        bool f:1;
    };
    unsigned char byte;
}mydata;


int main(void)
{
    mydata d;

    d.a=1;
    d.b=0;
    d.c=1;
    d.d=0;

printf("outupt = %hhX", d.byte);
}
0___________
  • 60,014
  • 4
  • 34
  • 74
  • No they are well-defined per _specific compiler_ for the specific hardware. If you are to change compiler at any point in the product's life time, it may not behave identically. Particularly when it comes to padding bits & bytes and supported types. – Lundin Sep 14 '20 at 06:28
  • Also, this code gives 0101, not 1010, assuming the compiler placed `a` at LSB, so it gives the wrong output on most compilers (but not guaranteed). – Lundin Sep 14 '20 at 06:30
  • @Lundin uC programming is very specific and people very rarely change the compiler, and most of the compilers for particular platform (for example Cortex M) follow the same path. Portability with AS-400 is not the issue which bothers uC developers. – 0___________ Sep 14 '20 at 07:23
  • I pretty much exclusively program microcontrollers and I quite often change compiler. This happens when the original programmer picked some freeware toolchain they found in a packet of corn flakes provided by the silicon vendor. Then eventually the team decides that they can't spend weeks of their time chasing IDE bugs (Eclipse, anyone?) or chase down non-existent tool support, then switch to a better toolchain. Also, most professional microcontroller systems implement MISRA-C and doing that will be a nightmare if you allow bit-fields. – Lundin Sep 14 '20 at 08:24
  • 1
    @P__J__: Maybe our embedded processors or SoCs are not that small, but it is still very deeply embedded. And we have here multiple core architectures on processor like a DSP + Cortex-M4 + Cortex-R5F. And since our ECUs are ASIL-B (and soon maybe higher), we need qualified compilers, which the gcc and clang are not. Not to mention, that the DSP compiler is a completely different compiler than the ARM core compilers. But the cores might share the same data between them. So, your answer is very biased. – kesselhaus Sep 14 '20 at 10:16