简体   繁体   中英

How to get and set bits for bits in char string?

Usually bit operations are done in smaller data width such as int, unsigned int or wchar_t. Assuming we want to use the bit strings in a longer format, how to shift, get and set bits for bits in char string?

One way may be to divide and conquer using the conventional method, but how do we ensure the bit carry over?

Given

#define numberOfState 2000  // number of bits
#define numberOfBitsIn1Byte 8

char* record;

int numberOfCharRequiredToRepresentBits = 
                     ceil(((float)numberOfState/(float)numberOfBitsIn1Byte));


record = (char*) malloc(sizeof(char)*numberOfCharRequiredToRepresentBits);
// record = "NAXHDKAN552ajdasdadNDfadsEBEAfA8gda5214S"; 
// optional : initialization by doing the set bit according to 
//            input from files. After which, do free(record);

How may we conduct bit operations such as to

i. shift the *record
ii. get bits from a specific bit position in *record
iii. set bits from a specific bit position in *record

Your bitstream is essentially an array of char. So, to perform these operations you work on these char elements.

i. The shifting operation depends on the number of bits you want to shift. If the number is a multiple of 8, it is pretty straightforward, you just copy the elements right of left as many bytes as the number is a multiple of 8. If the number is less than 8, you perform the operation on every element of the array, but you need to or the overflowing bits of the previous element. For example, in left shift, element i must incorporate the overflowing bits of element i+1, and on right shift, the overflowing bits of element i-1. Any other number of bits you want to shift can be achieved by a combination of these two actions. For example, a left shift by 18 is a shift by 16 followed by a shift by 2. In any case, you need to be careful on which side of the bitstring you start, so that you do not lose data.

ii. In order to get the n-th bit of the bitstream, you access the element with index n/8 (integer division) and get the n%8 bit from it.

iii. Pretty much the same as ii.

Please have a try with following code:

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

int isLittleEndian = 1;

void checkEndian(void)
{
    union  
    {  
        short   inum;  
        char c[sizeof(short)];  
    } un;  

    un.inum=0x0102;  

    if(un.c[0]==1 && un.c[1]==2) 
    {
        printf("big_endian.\n"); 
        isLittleEndian = 0;
    }
    else if(un.c[0]==2 && un.c[1]==1)
    {
        printf("little_endian.\n"); 

        isLittleEndian = 1;
    }

}

void shift_L(char *src, char * dst, int len, int n)
{
    int shiftBytes = n/8;
    int shiftBits = n%8;

    memset(dst, 0, len);
    memcpy(dst, src + shiftBytes, len - shiftBytes);

    if (shiftBits)
    {
        int i = 0;
        unsigned short tmp = 0;

        for ( i = 0; i < len; i++)
        {
            if (isLittleEndian)
            {
                tmp = *(dst+i) << 8 | *(dst+i+1);
                tmp <<= shiftBits;
                *(dst+i) = *((char *)&tmp + 1);
            }
            else
            {
                tmp = *(short *)(dst+i);
                tmp <<= shiftBits;
                *(dst+i) = *((char *)&tmp);
            }
        }
    }
}

void shift_R(char *src, char * dst, int len, int n)
{
    int shiftBytes = n/8;
    int shiftBits = n%8;

    memset(dst, 0, len);
    memcpy(dst + shiftBytes, src, len - shiftBytes);

    if (shiftBits)
    {
        int i = 0;
        unsigned short tmp = 0;

        for ( i = len -1; i >= 0; i--)
        {
            if (isLittleEndian)
            {
                tmp = *(dst+i-1) << 8 | *(dst+i);
                tmp >>= shiftBits;
                *(dst+i) = *((char *)&tmp);
            }
            else
            {
                tmp = *(short *)(dst+i-1);
                tmp >>= shiftBits;
                *(dst+i) = *((char *)&tmp+1);
            }
        }
    }
}

int getBit(char *src, int n)
{
    unsigned char tmp = *(src + n/8);
    unsigned char mask = (0x1 << (8 - n%8 - 1));
    int bit = 0;

    bit =  (tmp & mask) > 0;
    printf("%d", bit);
}

void setBit(char *src, int n, int bit)
{
    unsigned char * pTmp = src + n/8;
    unsigned char mask = (0x1 << (8 - n%8 - 1));

    if (bit)
    {
        *pTmp |= mask;
    }
    else
    {
        *pTmp &= ~mask;
    }
}

void dumpBin(unsigned char *src, int len)
{
    int i = 0;
    int j = 0;
    unsigned char mask = 0;

    for ( i = 0; i < len; i++)
    {
        for ( j = 0; j < 8; j++)
        {
            mask = 0x1 << 8 - j - 1;
            printf("%d",(*(src + i) & mask) > 0); 
        }    
    }
}

void main()
{
    char *record = "NAXHDKAN552ajdasdadNDfadsEBEAfA8gda5214S";
    //char *record = "NAXHDKA";

    int recordLen = strlen(record);
    char * buffer = NULL;
    int i = 0;

    checkEndian();

    recordLen = recordLen + recordLen%2;
    buffer = malloc(recordLen);
    memcpy(buffer, record, recordLen);

    printf("\n input bit stream:\n");
    dumpBin(buffer, recordLen);


    printf("\n bit stream from getBit:\n");
    for ( i = 0; i < recordLen*8; i++)
    {
        getBit(buffer, i);
    }


    setBit(buffer, 8, 1);
    setBit(buffer, 9, 0);
    setBit(buffer, 10, 1);
    setBit(buffer, 11, 1);
    printf("\n bit stream after setBit:\n");
    dumpBin(buffer, recordLen);


    shift_L(record, buffer, recordLen, 1);
    printf("\n bit stream after shift_L:\n");
    dumpBin(buffer, recordLen);


    shift_R(record, buffer, recordLen, 9);
    printf("\n bit stream after shift_R:\n");
    dumpBin(buffer, recordLen);

    printf("\n");

    free(buffer);

}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM