How to convert a byte array to a integer? - c

Lets say I have this byte
uint8_t k[8]= {0,0,0,1,1,1,0,0};
Is there a way to get this to become a single integer or hex?

If k represents 8 bytes of the 64-bit integer, go through the array of 8-bit integers, and shift them into the result left-to-right:
uint64_t res = 0;
for (int i = 0 ; i != 8 ; i++) {
res <<= 8;
res |= k[i];
}
The direction of the loop depends on the order in which the bytes of the original int are stored in the k array. The above snippet shows the MSB-to-LSB order; if the array is LSB-to-MSB, start the loop at 7, and go down to zero.
If the bytes represent individual bits, shift by one rather than eight.

This should do the trick:
int convertToInt(uint8_t k[8], bool leastSignificantFirst) {
int res = 0;
for (int i = 0; i < 8; ++i) {
if (leastSignificantFirst) {
res |= (k[i] & 1) << (7 - i);
} else {
res |= (k[i] & 1) << i;
}
}
return res;
}

Related

Effective bits calculation along the array in specified position on STM32

I'm wondering if someone know effective approach to calculate bits in specified position along array?
Assuming that OP wants to count active bits
size_t countbits(uint8_t *array, int pos, size_t size)
{
uint8_t mask = 1 << pos;
uint32_t result = 0;
while(size--)
{
result += *array++ & mask;
}
return result >> pos;
}
You can just loop the array values and test for the bits with a bitwise and operator, like so:
int arr[] = {1,2,3,4,5};
// 1 - 001
// 2 - 010
// 3 - 011
// 4 - 100
// 5 - 101
int i, bitcount = 0;
for (i = 0; i < 5; ++i){
if (arr[i] & (1 << 2)){ //testing and counting the 3rd bit
bitcount++;
}
}
printf("%d", bitcount); //2
Note that i opted for 1 << 2 which tests for the 3rd bit from the right or the third least significant bit just to be easier to show. Now bitCount would now hold 2 which are the number of 3rd bits set to 1.
Take a look at the result in Ideone
In your case you would need to check for the 5th bit which can be represented as:
1 << 4
0x10000
16
And the 8th bit:
1 << 7
0x10000000
256
So adjusting this to your bits would give you:
int i, bitcount8 = 0, bitcount5 = 0;
for (i = 0; i < your_array_size_here; ++i){
if (arr[i] & 0x10000000){
bitcount8++;
}
if (arr[i] & 0x10000){
bitcount5++;
}
}
If you need to count many of them, then this solution isn't great and you'd be better off creating an array of bit counts, and calculating them with another for loop:
int i, j, bitcounts[8] = {0};
for (i = 0; i < your_array_size_here; ++i){
for (j = 0; j < 8; ++j){
//j will be catching each bit with the increasing shift lefts
if (arr[i] & (1 << j)){
bitcounts[j]++;
}
}
}
And in this case you would access the bit counts by their index:
printf("%d", bitcounts[2]); //2
Check this solution in Ideone as well
Let the bit position difference (e.g. 7 - 4 in this case) be diff.
If 2diff > n, then code can add both bits at the same time.
void count(const uint8_t *Array, size_t n, int *bit7sum, int *bit4sum) {
unsigned sum = 0;
unsigned mask = 0x90;
while (n > 0) {
n--;
sum += Array[n] & mask;
}
*bit7sum = sum >> 7;
*bit4sum = (sum >> 4) & 0x07;
}
If the processor has a fast multiply and n is still not too large, like n < pow(2,14) in this case. (Or n < pow(2,8) in the general case)
void count2(const uint8_t *Array, size_t n, int *bit7sum, int *bit4sum) {
// assume 32 bit or wider unsigned
unsigned sum = 0;
unsigned mask1 = 0x90;
unsigned m = 1 + (1u << 11); // to move bit 7 to the bit 18 place
unsigned mask2 = (1u << 18) | (1u << 4);
while (n > 0) {
n--;
sum += ((Array[n] & mask1)*m) & mask2;
}
*bit7sum = sum >> 18;
*bit4sum = ((1u << 18) - 1) & sum) >> 4);
}
Algorithm: code is using a mask, multiply, mask to separate the 2 bits. The lower bit remains in it low position while the upper bit is shifted to the upper bits. Then a parallel add occurs.
The loop avoids any branching aside from the loop itself. This can make for fast code. YMMV.
With even larger n, break it down into multiple calls to count2()

How to write only 12 bits to a char array in C?

I'm trying to implement a FAT12 file system in which there's a FAT table data structure which is an unsigned char array. I need to write a function which given an array index would write a value to the next 12 bits (because it's FAT12) which is quite tricky because part of the value needs to go to one byte and the other part needs to go the half of the second byte.
This is the get value function I came up with:
//FAT is the unsigned char array
int GetFatEntry(int FATindex, unsigned char * FAT) {
unsigned int FATEntryCode; // The return value
// Calculate the offset of the WORD to get
int FatOffset = ((FATindex * 3) / 2);
if (FATindex % 2 == 1){ // If the index is odd
FATEntryCode = ((unsigned char)(&FAT[FatOffset])[0] + (((unsigned char)(&FAT[FatOffset])[1]) << 8));
FATEntryCode >>= 4; // Extract the high-order 12 bits
}
else{ // If the index is even
FATEntryCode = ((unsigned char)(&FAT[FatOffset])[0] + (((unsigned char)(&FAT[FatOffset])[1]) << 8));
FATEntryCode &= 0x0fff; // Extract the low-order 12 bits
}
return FATEntryCode;
}
I'm struggling to come up with the function which would set a value given a FATindex. I would appreciate any suggestions.
This seems to work. The data that should be written should be in the first 12 bits of data
void WriteFatEntry(int FATindex, unsigned char * FAT, unsigned char data[2]) {
// Calculate the offset of the WORD to get
int FatOffset = ((FATindex * 3) / 2);
unsigned char d;
if (FATindex % 2 != 0){ // If the index is odd
// Copy from data to d and e, and shift everything so that second half of
// e contains first half of data[1], and first half of e contains second
// half of data[0], while second half of d contains first half of data[0].
// First half of d contains a copy of first four bits in FAT[FatOffset]
// so that nothing changes when it gets written
unsigned char e=data[1];
e>>=4;
d=data[0];
e|=(d<<4) & 0b11110000;
d>>=4;
d |= FAT[FatOffset] & 0b11110000;
FAT[FatOffset]=d;
FAT[FatOffset+1] = e;
}
else{ // If the index is even
d = data[1] & 0b11110000;
d |= FAT[FatOffset+1] & 0b00001111;
FAT[FatOffset] = data[0];
FAT[FatOffset+1] = d;
}
}
#include <stdio.h>
#if 1 /* assuming MSB first */
#define MSB (idx)
#define LSB (idx+1)
#else /* assuming LSB first */
#define MSB (idx+1)
#define LSB (idx)
#endif
unsigned fat_getval(unsigned char * tab, unsigned num)
{
unsigned idx;
unsigned val;
idx = num + num/2;
val = (tab[MSB] <<8 ) + (tab[idx+1] ) ;
if (num %2 ==0) val >>= 4;
return val & 0xfff;
}
void fat_putval(unsigned char * tab, unsigned slot, unsigned val)
{
unsigned idx;
idx = slot + slot/2;
if (slot %2 ==0) { /* xyz_ */
val <<= 4;
val |= tab[LSB] & 0xf;
}
else { /* _xyz */
val |= (tab[MSB] & 0xf0) << 8;
}
tab[MSB] = val >>8;
tab[LSB] = val &0xff;
}
#undef MSB
#undef LSB
unsigned char fattable[] = "\x01\x23\x45\x67\x89\xab"; // 12 nibbles
int main(void)
{
unsigned idx, ret;
for (idx = 0; idx < 6; idx++) { // 6 bytes -> 12 nibbles */
printf(" %02x", fattable[idx] );
}
printf("\n");
printf("Put(0,0xabc):\n");
fat_putval(fattable, 0, 0xabc);
for (idx = 0; idx < 6; idx++) {
printf(" %02x", fattable[idx] );
}
printf("\n");
printf("Put(3,0xdef):\n");
fat_putval(fattable, 3, 0xdef);
for (idx = 0; idx < 6; idx++) {
printf(" %02x", fattable[idx] );
}
printf("\n");
printf("Get(0 to 4):\n");
for (idx = 0; idx < 4; idx++) { // 12 / 3 ~> 4 * 12bit entries
ret = fat_getval( fattable, idx);
printf("%u := %x\n", idx, ret );
}
printf("\n");
return 0;
}

Bitwise shifting array of char's

I have got an array of chars that I'm trying to bitwise shift right >>, then & with another array. I think I have got the wrong idea of how to do this.
I thought, even though it was an array of chars just stating my_array >>= 1 would shift everything but I am getting an error: "error: invalid operands to binary >> (have ‘char[8]’ and ‘int’)"
The bitwise comparision I am trying to do is with a similar size array initiated to all "0's"...for that I'm getting: "error: invalid operands to binary & (have ‘char *’ and ‘char *’)"
Do I need to convert these array's into something else before I can shift and compare?
Sorry, I was not super clear... All great advice up to this point and I think I am realizing more that there is no super easy way to do this. More specifically, what I am trying to do is shift the bits of the WHOLE char array right 1, adding the bit shifted off the right back to the left most side of the array, do the bitwise compare with another array of same size.
Technically the compare doesn't have to be array with array... I just need the bits. Would it be easier to convert the array's to something else before trying to do the shifts/comparisons?
You have to shift and compare elementwise.
for(i = 0; i < len; ++i)
array[i] >>= 3;
for example. If you want to move the bits shifted out of one element to the next, it's more complicated, say you're shifting right, then
unsigned char bits1 = 0, bits2 = 0;
for(i = len-1; i >= 0; --i) {
bits2 = array[i] & 0x07;
array[i] >>= 3;
array[i] |= bits1 << 5;
bits1 = bits2;
}
traversing the array in the other direction because you need the bits from the next higher slot.
You'll have to shift the entries in the array one by one. (And if you want to compare two of these, you'll need to do it element by element.)
If you were hoping that bits shifted off each char would get shifted into the next one, you'll need to take care of that manually too.
If you are wanting that shift-into-the-next-byte behaviour, and don't mind making your code nasty and nonportable and bug-prone, you might be able to take a pointer to the array, cast it to something like unsigned long long *, dereference it and shift the resulting integer, and store it back again.
BUT if that's the behaviour you want then you should be using an integer instead of a char[8] to begin with.
(If you could say more about what you're actually aiming to achieve, then more helpful answers may be possible.)
If you want to perform operations such as shifting / OR / XOR / AND / etc.. on arrays, you should perform it in a loop, you cannot perform it directly on the array.
/** Shift an array right.
* #param ar The array to shift.
* #param size The number of array elements.
* #param shift The number of bits to shift.
*/
void shift_right(unsigned char *ar, int size, int shift)
{
int carry = 0; // Clear the initial carry bit.
while (shift--) { // For each bit to shift ...
for (int i = size - 1; i >= 0; --i) { // For each element of the array from high to low ...
int next = (ar[i] & 1) ? 0x80 : 0; // ... if the low bit is set, set the carry bit.
ar[i] = carry | (ar[i] >> 1); // Shift the element one bit left and addthe old carry.
carry = next; // Remember the old carry for next time.
}
}
}
You can shift only members of that arrays, a char (or an int). You can't shift an entire array. Shifting my_array tries to perform a shift operation on an array type (or a pointer to char) which is impossible. Do this instead:
for (i = 0; i < size; i++) {
my_array[i] >>= 1;
}
Also you must be careful with chars because they are usually signed, and a char containing a negative value will bring '1' from the left instead of zeros. So you better use unsigned chars.
EDIT:
The code above is simplistic. If you intended to shift right the array as a whole, not just each byte on its own, then you need to "manually" copy each LSB to the MSB of the byte to its right. Take a loop at the answer of Richard Pennington.
/**
* shift a number of bits to the right
*
* #param SRC the array to shift
* #param len the length of the array
* #param shift the number of consecutive bits to shift
*
*/
static void shift_bits_right(uint8_t SRC[], uint16_t len, uint32_t shift) {
uint32_t i = 0;
uint8_t start = shift / 8;
uint8_t rest = shift % 8;
uint8_t previous = 0;
for(i = 0; i < len; i++) {
if(start <= i) {
previous = SRC[i - start];
}
uint8_t value = (previous << (8 - rest)) | SRC[i + start] >> rest;
SRC[i + start] = value;
}
}
I know this is old topic but i was not satisfied with the answers available, here is something i wrote recently which allows you to specify the amount of bits you can shift by and also there is simple XOR encryption in it.
//https://github.com/ashvin-bhuttoo/CryptoTest/blob/master/CryptoTest/Crypto.cpp
//CRYPTO CONFIGURATION PARAMETERS
#define BIT_SHIFT 3
#define XOR_KEY 0x3C
#define ENABLE_XOR_VARIANCE true
////////////////////////////////
int get_rs_mask(int shift)
{
switch (shift)
{
case 0:
return 0x00;
case 1:
return 0x01;
case 2:
return 0x03;
case 3:
return 0x07;
case 4:
return 0x0F;
case 5:
return 0x1F;
case 6:
return 0x3F;
case 7:
return 0x7F;
default:
throw "get_rs_mask -> Error, shift argument outside legal range 0-7";
}
}
void shift_right(char* buf, int msg_len, int shift)
{
unsigned char tmp = 0x00, tmp2 = 0x00;
for (int k = 0; k <= msg_len; k++)
{
if (k == 0)
{
tmp = buf[k];
buf[k] >>= shift;
}
else
{
tmp2 = buf[k];
buf[k] >>= shift;
buf[k] |= ((tmp & get_rs_mask(shift)) << (8 - shift));
if (k != msg_len)
tmp = tmp2;
}
}
}
int get_ls_mask(int shift)
{
switch (shift)
{
case 0:
return 0x00;
case 1:
return 0x80;
case 2:
return 0xC0;
case 3:
return 0xE0;
case 4:
return 0xF0;
case 5:
return 0xF8;
case 6:
return 0xFC;
case 7:
return 0xFE;
default:
throw "get_ls_mask -> Error, shift argument outside legal range 0-7";
}
}
void shift_left(char* buf, int msg_len, int shift)
{
char tmp = 0x00, tmp2 = 0x00;
for (int k = msg_len; k >= 0; k--)
{
if (k == msg_len)
{
tmp = buf[k];
buf[k] <<= shift;
}
else
{
tmp2 = buf[k];
buf[k] <<= shift;
buf[k] |= ((tmp & get_ls_mask(shift)) >> (8 - shift));
tmp = tmp2;
}
}
}
void crypt(char* buf, int msg_len, bool decrypt = false)
{
if (!decrypt)
{
shift_right(buf, msg_len, BIT_SHIFT);
for (int k = 0; k < msg_len; k++)
{
buf[k] = buf[k] ^ XOR_KEY ^ k * (ENABLE_XOR_VARIANCE ? 2 : 0);
}
buf[msg_len] = '\0';
}
else
{
for (int k = 0; k < msg_len; k++)
{
buf[k] = buf[k] ^ XOR_KEY ^ k * (ENABLE_XOR_VARIANCE ? 2 : 0);
}
shift_left(buf, (msg_len)-1, BIT_SHIFT);
}
}
/**
* Shift a number of bits to the right
*
* #param array The array to shift
* #param len The length of the array
* #param shift The number of consecutive bits to shift. To the right if shift is positif.
*
*/
static void shift_bits_right(uint8_t *array, int len, int shift) {
uint8_t macro_shift = shift / 8;
shift = shift % 8;
uint8_t array_out[len];
memset(array_out, 0, len);
for(int i = 0; i < len; i++) {
if(i+macro_shift < len)
array_out[i+macro_shift] += array[i]>>shift;
if(i+macro_shift+1 < len)
array_out[i+macro_shift+1] += array[i]<<(8-shift);
}
memcpy(array, array_out, len);
}
For everyone who is looking for a code snippet to (logically) shift right a byte array that actually works:
template<size_t N> void shift_right(array<uint8_t, N>& arr, uint64_t bits)
{
int64_t num_bytes = bits / 8;
int64_t num_bits = bits % 8;
for(int64_t i = N-1; i >= 0; i--)
{
int64_t i_from = i - num_bytes;
int64_t i_from_minus_one = i - num_bytes - 1;
uint8_t v_from = i_from < 0 ? 0 : arr[i_from];
uint8_t v_from_minus_one = i_from_minus_one < 0 ? 0 : arr[i_from_minus_one];
arr[i] = v_from >> num_bits | v_from_minus_one << (8 - num_bits);
}
}

I am getting the output in Big Endian Format

#include <stdio.h>
int main()
{
int num, i = 0,pos;
printf(" Enter num \n");
scanf("%d",&num);
for( i = 0; i < 31; i++ )
{
pos = 1 << i;
if ( num & pos )
printf("1");
else
printf("0");
}
printf("\n");
return 0;
}
/*
O/P
Enter Num
12
0011000000000000
*/
But i want to print the o/p as 0000000000001100
So, What are the changes i have to made to get the desired o/p
You're printing the least significant bit first. Change your for loop to count down:
for (int i = 31; i >= 0; i--)
EDIT:
Seem that I'm the one who overlooked desired output. So the solutions provided by others will work for the OP.
I'm surprised people overlooked the fact that endianness usually applies to byte level instead of bit, which make the plain index-based loop fail to provide required output.
for a decimal to big-endian byte, you need :
while (num)
{
big <<= 8;
big |= num & 0xFF;
num >>= 8;
}
so in order to output little-endian integer into big-endian binaries, you need :
// 'num' was 4-byte (int) data in little-endian format
while (num)
{
// select required byte block
unsigned char curByte = num & 0xFF;
// prints the byte binaries
for(int iBit=7; iBit>=0; --iBit)
{
unsigned char theBit = curByte >> iBit;
if (theBit & 0x1)
putchar('1');
else
putchar('0');
}
// shifts to next byte block
num >>= 8;
}
Change your for loop to be more like:
#define BIT(x) (1U << (x))
for (i = 31; i >= 0; --i)
{
if (x & BIT(i)) {
putchar('1');
}
else {
putchar('0');
}
}

Bytes to Binary in C

I'm trying to simply convert a byte received from fget into binary.
I know the value of the first byte was 49 based on printing the value. I now need to convert this into its binary value.
unsigned char byte = 49;// Read from file
unsigned char mask = 1; // Bit mask
unsigned char bits[8];
// Extract the bits
for (int i = 0; i < 8; i++) {
// Mask each bit in the byte and store it
bits[i] = byte & (mask << i);
}
// For debug purposes, lets print the received data
for (int i = 0; i < 8; i++) {
printf("Bit: %d\n",bits[i]);
}
This will print:
Bit: 1
Bit: 0
Bit: 0
Bit: 0
Bit: 16
Bit: 32
Bit: 0
Bit: 0
Press any key to continue . . .
Clearly, this is not a binary value. Any help?
The problem you're having is that your assignment isn't resulting in a true or false value.
bits[i] = byte & (mask << i);
This gets the value of the bit. You need to see if the bit is on or off, like this:
bits[i] = (byte & (mask << i)) != 0;
Change
bits[i] = byte & (mask << i);
to
bits[i] = (byte >> i) & mask;
or
bits[i] = (byte >> i) & 1;
or
bits[i] = byte & 1;
byte >>= 1;
One way, among many:
#include <stdio.h>
#include <limits.h>
int main(void) {
int i;
char bits[CHAR_BIT + 1];
unsigned char value = 47;
for (i = CHAR_BIT - 1; i >= 0; i -= 1) {
bits[i] = '0' + (value & 0x01);
value >>= 1;
}
bits[CHAR_BIT] = 0;
puts(bits);
return 0;
}
You may notice that your output has a couple 1's and 0's, but also powers of 2, such as 32. This is because after you isolate the bit you want using the mask, you still have to bit-shift it into the least-significant digit so that it shows up as a 1. Or you could use what other posts suggested, and instead of bit-shifting the result (something like 00001000 for example), you could simply use (result != 0) to fetch either a 1 or 0, since in C, false is 0, and comparisons such as != will return 1 as true (I think).
#include<Stdio.h>
#include <limits.h>
void main(void) {
unsigned char byte = 49;// Read from file
unsigned char mask = 1; // Bit mask
unsigned char bits[8];
int i, j = CHAR_BIT-1;
// Extract the bits
for ( i = 0; i < 8; i++,j--,mask = 1) {
// Mask each bit in the byte and store it
bits[i] =( byte & (mask<<=j)) != NULL;
}
// For debug purposes, lets print the received data
for (int i = 0; i < 8; i++) {
printf("%d", bits[i]);
}
puts("");
}
This addition in place of that will work:
bits[i]= byte & (mask << i);
bits[i] >>=i;

Resources