-1

I'm trying to create a table in "c" (for an embedded application) where each row is a sequence of 8 bits, for example:

11010011
01010011
10000000

then I need to have functions to set/clear/read any bit in any row. What is the most efficient way to do that?

For bit manipulation I thought to use:

uint8_t msk = 0x01;
row3 |= msk;

But to do this I think I need to define row3 (and every row) as uint8_t and convert it to hexadecimal as well, and that leads me to my second question:

how to store an 8-bit binary sequence in a uint8_t? I've seen different ways to do similar tasks like the one discussed here but none of them worked for me. Can you help me? Thanks.

too honest for this site
  • 12,050
  • 4
  • 30
  • 52
Kalkhouri
  • 341
  • 1
  • 6
  • 16
  • Ponder x[n>>3] |= 1<<(n&7); x[n>>3]&=(~(1<<(n&7))); – old_timer Jul 20 '18 at 21:29
  • 1
    not sure where you are going with hexadecimal, thought you wanted to do bit manipulation not conversion to/from ascii – old_timer Jul 20 '18 at 21:29
  • 2
    Please ask one question per post. You mention `row3` but the question does not define it, or any row. Please post the [Minimal, Complete, and Verifiable example](http://stackoverflow.com/help/mcve) that shows the problem. Show the input, the expected output, and the actual output. – Weather Vane Jul 20 '18 at 21:32
  • 1
    *none of them worked for me* does not give us any clues as to: 1. What did you try in code? 2. What parts of the code did not work? 3. In what way did they not work? – R Sahu Jul 20 '18 at 21:33
  • a uint8_t is 8 bits. you can store 8 bits. you want to call them a sequence the only other question is which is the first bit and which is the eightj bit? and if a sequence are you shifting them in and out rather than individually accessing them? – old_timer Jul 20 '18 at 21:33
  • Okay nevermind on my first comment, both it and the link you posted are your answer, but it is a case of understanding what is going on and how to use it...So this is truly a case of show us your code that didnt work, what you think it should have done and what it did instead. – old_timer Jul 20 '18 at 21:35
  • Regarding row3 I mean the third raw of my example and it is not defined in the code because I don't know what to define it and that's my main question. I guess I can summarize my problem as follows: how to store this value: 1000000 and then modify it's first bit so it becomes 10000001? maybe a simple answer to this question can give me an idea how to proceed. Thanks – Kalkhouri Jul 20 '18 at 21:55
  • You can store that value with `row3 = 0x40;` – Barmar Jul 20 '18 at 22:02
  • the input can only be a sequence of bits "10000000" and not an equivalent hex 0x40. I will try to edit my question to make it more clear. Thanks – Kalkhouri Jul 20 '18 at 22:08
  • I am not convinced that the marked duplicate is at all related to this question. I would say that this question is entirely unclear. How is the sequence of 8 bits represented is not already a `uint8_t`? Show the table as the code you are using to represent it. – Clifford Jul 20 '18 at 22:33
  • Where is the "input" coming from? Is it a string of ASCII '1' / `0` characters? That would be unusual for an embedded system. The nature of your embedded system and how these "tables" are represented needs to be clear. If the data is arriving at run-time, you need ot be clear about how it is received. – Clifford Jul 20 '18 at 23:05
  • 2
    Note that _"convert it to hexadecimal as well"_ is wrong-thinking. You need to convert it to a `uint8_t` - hex is only a source code representation of an integer. `0x0c`, `12`, `014` and `'\x0c'` all represent the same integer value in hex, decimal, octal and a character literal constant and any could be assigned to a `uint8_t` and would generate identical machine level code. – Clifford Jul 20 '18 at 23:11

3 Answers3

2

To represent binary bit patterns in C, it is normal to use hexadecimal notation. The utility of hex is that a single hex digit exactly coincides with 4 binary digits, so with experience you can quickly convert between the 16 hex digits and the corresponding binary value in your head, and for longer integers it is simply a matter of converting each digit in turn - 4 bits at a time. Representing long integers in binary quickly becomes impractical.

So your table might be represented as:

uint8_t row[] = { 0xd3, // 11010011
                  0x53, // 01010011
                  0x80  // 10000000
                } ;

Then you set/clear bits in the following manner:

row[2] |= mask ;  // Set mask bits
row[0] &= mask ;  // Clear mask bits

To create a mask specifying numbered bits without hard-coding the hex value you can use an expression such as:

uint8_t mask = 1<<7 | 1<<5 | 1<<0 ;  // 10100001 mask bits 0, 5 & 7

Occasionally a "visual" binary representation is desirable - for character bitmaps for example, the character A is much easier to visualise when represented in binary:

00000000  
00011000  
00100100  
01000010  
01111110  
01000010  
01000010  
00000000  

It is possible to efficiently code such a table while maintaining the "visualisation" by exhaustively defining a macro for each binary value; e.g:

#define B_00000000 0x00 
#define B_00000001 0x01 
#define B_00000010 0x02 
#define B_00000011 0x03 
#define B_00000100 0x04 
...
#define B_11111110 0xfe 
#define B_11111111 0xff

Note to create the above macros, it is best perhaps to write a code generator - i.e. a program to generate the code, and put the macros in a header file.

Given such macros you can then represent your table as:

uint8_t row[] = { B_11010011
                  B_01010011
                  B_10000000
                } ;

or the character bitmap for A thus:

uint8_t charA[] = { B_00000000,  
                    B_00011000,  
                    B_00100100,  
                    B_01000010,  
                    B_01111110,  
                    B_01000010,  
                    B_01000010,  
                    B_00000000 } ;

In the case that the bits are received at run-time serially, then the corresponding uint8_t can be built using sequential mask and shift:

uint8_t getByte()
{
    uint8_t mask = 0x80 ;
    uint8_y byte = 0 ;

    while( mask != 0 )
    {
        uint8_t bit = getBit() ;
        byte |= bit ? mask : 0 ;
        mask >>= 1 ;
    }

    return byte ;
}

What the getBit() function does is for you to define; it may read a file, or a string, or keyboard entry for example, but it must return either zero or non-zero or the binary digits 0 and 1 respectively. If the data is received LSB first then the mask starts from 0x01, and a << shift used instead.

Clifford
  • 88,407
  • 13
  • 85
  • 165
0

C doesn't have a syntax for entering binary literals, so you should type them as octal or hex, e.g.

uint8_t row1 = 0xd3;
uint8_t row2 = 0x53;
uint8_t row3 = 0x80;

See How do you set, clear, and toggle a single bit? for how you can manipulate specific bits.

row3 |= mask;

will set the bits that are set in mask.

Barmar
  • 741,623
  • 53
  • 500
  • 612
0

If I understand correctly, you require a list of hexadecimal numbers and you would like to manipulate the bits in any of the elements of the list. I would approach it by making an array of unsigned integers with the size of the array being defined by the number of elements you need in your table.

    #include <stdio.h>
    #include <stdint.h>
    #define LIST_SIZE 3

    //accepts the array and sets bit_pos bit of the list idx
    int set_bit(uint8_t* hex_list, int list_idx, int bit_pos){
        hex_list[list_idx] = hex_list[list_idx] | 0x01<<bit_pos; //left shift by the bit position you want to set
    }

    int clear_bit(uint8_t* hex_list, int list_idx, int bit_pos){
        hex_list[list_idx] = hex_list[list_idx] & ~(0x01<<bit_pos); //left shifts and does logical inversion to get the bit to clear
    }

    int main(void) {
        uint8_t hex_list[LIST_SIZE] = {0x00, 0x01, 0x02};
        set_bit(hex_list, 0, 1); // will make 0th element 0x00-> 0x02 by seting bit position 1
        clear_bit(hex_list, 1,0); //will make 1st element 0x01-> 0x00 by clearing bit position 0

        set_bit(hex_list, 2, 0); // will make 2nd element 0x02->0x03 by setting bit at position 1
        clear_bit(hex_list, 2 , 0);// will make 2nd element 0x03 ->0x02 by clearing bit at position 0

        //print the result and verify
        for(int i = 0; i<LIST_SIZE; ++i){
            // modified array will be {0x02, 0x00, 0x02}
            printf("elem%d = %x \n", i, hex_list[i]); 
        }
        return 0;
    }

An uint8_t in represents a 8-bit unsigned integer whose value can vary between 0(binary representation = 00000000)to 255(binary representation = 11111111).

kaala1993
  • 1
  • 1