is it possible to bit mask a char array - c

Let's say I have the following char array
char array[32];
I want to use only the 10 most significant bits of this array as a hash value.
Is it possible to use bitwise operation on this char array?
If so, how should i do it?

Assuming your implementation has 8-bit char, and that you have a 256-bit number stored in big endian in this array, here how to access the 10 msb of the 256-bit number.
uint16_t a;
a = (array[0] << 2 | (array[1] & 0xC0) >> 6) & 0x3FF;

I'm pretty sure you want something like this (again assuming 8-bit chars stored big endian in array):
uint16_t a = (((uint16_t)array[0] & 0xFF) << 2 | ((uint16_t)array[1] & 0xFF) >> 6) & 0x3FF;
To break that down a bit:
uint16_t byte0 = (uint16_t)array[0] & 0xFF;
uint16_t byte1 = (uint16_t)array[1] & 0xFF;
uint16_t a = (byte0 << 2 | byte1 >> 6) & 0x3FF;

Related

Store a 2byte value in memory location in C

I am in need of your help in this problem:
I want to store a 2 byte number in a char array I have tried the below 2 logics but both have failed
char buff[10];
char* ptr = buff;
/*
I want to store a 2 byte value say 750
Method 1 */
short a = 750;
*(++ptr)=a; //Did not work got these values in first 2 bytes in buffer: 0xffffffc8 0xffffffef
/* Method 2 */
short *a=750;
memcpy(++ptr,a,2) // Got segmentation fault
I know I can do this by dividing by 256 but I want to use a simpler method
*ptr++=750/256;
*ptr=750%256;
The easiest way is simply:
uint16_t u16 = 12345;
memcpy(&buff[i], &u16, 2);
memcpy will place the data according to your CPU endianess.
Alternatively you can bit shift, but since bit shifts themselves are endianess-independent, you need to manually pick the correct indices for buff according to endianess.
Memory layout like Little Endian:
buff[i] = u16 & 0xFFu;
buff[i+1] = (u16 >> 8) & 0xFFu;
Memory layout like Big Endian:
buff[i] = (u16 >> 8) & 0xFFu;
buff[i+1] = u16 & 0xFFu;
char buff[10];
short a=1023;
//To store in char array
buff[0] = a & 0xff;
buff[1] = (a >> 8) & 0xff;
// To get original value.
short b = ((buff[1] << 8) & 0xff00) | (buff[0] & 0x00ff);

How to make a word from Byte []?

I am new to programming world, I want to convert two bytes into a word.
So basically, I have a Byte array where index 0 is Buffer[0]=08 and index 1 is Buffer[1]=06
I want to create a word from these two bytes
where word ETHType to be 0x0806
You would use bitwise operators and bit shifting.
uint16_t result = ((uint16_t)Buffer[0] << 8) | Buffer[1];
This does the following:
The value of Buffer[0] is shifted 8 bits to the left. That gives you 0x0800
A bitwise OR is performed between the prior value and the value of Buffer[1]. This sets the low order 8 bits to Buffer[1], giving you 0x0806
word ETHType = 0;
ETHType = (Buffer[0] << 8) | Buffer[1];
edit: You should probably add a mask to each operation to make sure there is no bit overlap, and you can do it safely in one line.
word ETHType = (unsigned short)(((unsigned char)(Buffer[0] & 0xFF) << 8) | (unsigned char)(Buffer[1] & 0xFF)) & 0xFFFF;
Here's a macro I use for this very thing:
#include <stdint.h>
#define MAKE16(a8, b8) ((uint16_t)(((uint8_t)(((uint32_t)(a8)) & 0xff)) | ((uint16_t)((uint8_t)(((uint32_t)(b8)) & 0xff))) << 8))

Converting bytes array to integer

I have a 4-byte array (data) of type uint8_t, which represents a speed data integer. I'm trying to cast this array to uint32_t integer (speed), multiply this speed by 10 and then restore it back to the 4-byte array (data). The data format is clear in the code below.
I always get the error:
"assignment to expression with array type"
The code:
volatile uint8_t data[4] = {0x00 , 0x00, 0x00, 0x00};
volatile uint32_t speed;
speed=( uint32_t)*data;
speed=speed*10;
data=(uint8_t*)speed;
To be safe according endianess, portable and secure, you should recreate your data:
speed = ((uint32_t)data[0]) << 24
| ((uint32_t)data[1]) << 16
| ((uint32_t)data[2]) << 8
| ((uint32_t)data[3]);
or
speed = ((uint32_t)data[3]) << 24
| ((uint32_t)data[2]) << 16
| ((uint32_t)data[1]) << 8
| ((uint32_t)data[0]);
Choose solution according position of most significant byte
You get an "assignment to expression with array type" error because you can't assign directly an array: data=(uint8_t*)speed; is totally forbidden in C, you definitively can't have an array for lvalue. You have to do inverse operation:
data[0] = (uint8_t)((speed >> 24) & 0x00FF);
data[1] = (uint8_t)((speed >> 16) & 0x00FF);
data[2] = (uint8_t)((speed >> 8) & 0x00FF);
data[3] = (uint8_t)(speed & 0x00FF);
or, according position of most significant byte:
data[3] = (uint8_t)((speed >> 24) & 0x00FF);
data[2] = (uint8_t)((speed >> 16) & 0x00FF);
data[1] = (uint8_t)((speed >> 8) & 0x00FF);
data[0] = (uint8_t)(speed & 0x00FF);
EDIT
Don't use cast or memcpy as mention in commentaries and original answer: in addition of non portability issues, you will have security issues, according alignment restrictions and aliasing rules on some platform, compiler can generate incorrect code - thanks to user694733 | see here - thanks to Lundin
speed = *((uint32_t *)data); // DANGEROUS NEVER USE IT
*((uint32_t *)data) = speed; // DANGEROUS NEVER USE IT
Your code doesn't work because during data=(uint8_t*)speed; you don't get a "lvalue" for data, you just get an array type which can't be used in assignment or any form of arithmetic. Similarly, speed=( uint32_t)*data; is a bug because that only gives you the first item in the array.
The only correct way you should do this:
volatile uint8_t data[4] = {0x00 , 0x00, 0x00, 0x00};
volatile uint32_t speed;
speed = (uint32_t)data[0] << 24 |
(uint32_t)data[1] << 16 |
(uint32_t)data[2] << 8 |
(uint32_t)data[3] << 0;
speed=speed*10;
data[0] = (uint8_t) ((speed >> 24) & 0xFFu);
data[1] = (uint8_t) ((speed >> 16) & 0xFFu);
data[2] = (uint8_t) ((speed >> 8) & 0xFFu);
data[3] = (uint8_t) ((speed >> 0) & 0xFFu);
This is 100% portable and well-defined code. No implicit promotions take place. This code does not rely on endianess or other implementation-defined behavior. Why write code that does, when you can write code that doesn't?

Does bit-shifting properly isolate bytes on different endian systems?

I'm attempting to write an integer to a byte buffer. Will the following code always write in big endian format, regardless of the endianness of the system:
byte[0] = (uint8_t) (val & 0xFF000000) >> 24;
byte[1] = (uint8_t) (val & 0x00FF0000) >> 16;
byte[2] = (uint8_t) (val & 0x0000FF00) >> 8;
byte[3] = (uint8_t) (val & 0x000000FF);
Unfortunately, I don't have access to htonl() and similar functions.
Yes, this will work correctly. The bit-shifting operators deal with the abstract numeric values, not the way they're represented in the hardware registers or RAM. >> N is essentially equivalent to dividing by 2N.

Type conversion

Can someone please tell me what do these lines of code do
*(a++) = (int)((value >> 16) & 0xFF) ;
*(a++) = (int)((value >> 8) & 0xFF) ;
*(a++) = (int)((value & 0xFF)) ;
I understand that it checks the value, if it is much greater than 16 it converts it to type int and if it is much smaller than 8 does the same. But what does the
& 0xFF and *(a++) do?
I understand that it checks the value
It doesn't check anything, it's not like the << symbol in math which means "much smaller". To break down this line:
*(a++) = (int)((value >> 16) & 0xFF);
(>>) shifts value 16 times to the right
(&) ands the result with 0xFF, thereby discarding everything to the left
Stores the result at the address pointed by a
Increments the pointer, making a point to some "next" element
(value>>16)
No it is not much greater.
It is shift right by 16 bits.
But dividing it by 2 exatly 16 times makes it much smaller than before.
val&0xff makes a solution if it is divisible by 256. For example: if val&0xff is different than zero, than it is not divisible by 256
Given:
char data[10];
uint32_t value = 0x61626364; // 'abcd'
char *a = data;
*(a++) = (int)((value >> 24) & 0xFF);
*(a++) = (int)((value >> 16) & 0xFF);
*(a++) = (int)((value >> 8) & 0xFF);
*(a++) = (int)(value & 0xFF);
*(a++) = ':';
*((uint32_t *)a) = value;
a+=4;
*(a++) = 0;
printf("%s\n", data);
I get (on my intel box, which is a little endian system):
abcd:dcba
So this is ensuring that the bytes of an integer are in an platform-independent form (choosing big endian as the byte format).
Now, for:
*(a++) = (int)((value >> 16) & 0xFF);
we have:
0x61626364 -- value
0x00006162 -- value >> 16 : shifted 2 bytes
0x00000062 -- (value >> 16) & 0xFF : last byte only
*(a++) = (int)((value >> 16) & 0xFF) ;
is like:
aIntValue = value/65536;
aIntBalue = a%256;
*(a++) = (int)((value >> 8) & 0xFF) ;
is like:
aIntValue = value/256;
aIntValue = a%256;
*(a++) = (int)((value & 0xFF)) ;
is like:
aIntValue = a%256;
At the end of the code, either code assign the aIntValut to the value pointed to the pointer 'a' and next the pointer is moved to the next element.

Resources