I have a uint8_t array that contains two elements:
uint8_t ui8[2]; // uint8_t array
ui8[0] = 70; // LSB
ui1[1] = 60; // MSB
I want to get a uint16_t number (not an array) from these two uin8_t values. I used this approach in order to get this result: uint16_t ui16 = 6070
uint16_t ui16 = ui8[1] | (ui8[0] << 8);
But I got uint16_t ui16 = 15430;
Am using the wrong method to get what I need? Or is there something missing?
Maybe you meant to work with hexadecimal numbers :
uint8_t ui8[2]; // uint8_t array
ui8[0] = 0x70; // LSB
ui1[1] = 0x60; // MSB
uint16_t ui16 = ui8[1] | (ui8[0] << 8);
printf("%x\n", ui16); // 7060
If you want to work with decimal number, when you need to multiply the "MSB" by 100 and add them. It's far more uncommon to work with decimal number for that.
uint8_t ui8[2]; // uint8_t array
ui8[0] = 70; // LSB
ui1[1] = 60; // MSB
uint16_t ui16 = ui8[1] + (ui8[0] * 100);
printf("%d\n", ui16); // 7060
Please not than in both case, "70" will be before the "60", because you're shifting the first element of the array (70). The 70 will be the MSB.
you can also use union punning for it:
#include <stdio.h>
#include <stdint.h>
typedef union {
uint8_t u8[2];
uint16_t u16;
}data16;
int main() {
data16 d16;
d16.u8[0] = 0x60;
d16.u8[1] = 0x70;
printf("%hx\n", d16.u16);
// it works in the opposite direction as well
// lets try to store 7060 decimal in two bytes
d16.u16 = 7060u;
printf("storing %hu decimal in two bytes: LSB:0x%0hhx (%hhu decimal), MSB:0x%0hhx (%hhu decimal)\n", d16.u16, d16.u8[0], d16.u8[0], d16.u8[1], d16.u8[1]);
return 0; }
uint8_t ui8[2]; // uint8_t array
ui8[0] = 70; // LSB
ui1[1] = 60; // MSB
To copy the both values into a uint16, you can do as below:
uint16_t output = 0;
output |= (uint16_t)ui8[0] << 8;
output |= (uint16_t)ui8[1] << 0;
You can use the similar logic for writing the uint32_t/uint64_t from the array of uint8_t.
Related
I am getting the input data from my microcontroller over uint8 data the are transmitted as 0xff, 0x2a.... the the two bits are subsequntly high and low values.
I need to convert this to uint_32 var where i can use memcpy
example
1C 1D 1E 1F 20 21 22 23
if this are the VALUES that are transferred how i can get them all in a single uint32 variable, with this below approach i can just get the last two bits which is just 23 and not the entire
void Func(const uint8_t * data){
uint32_t msgh =0;
uint32_t msgl=0;
uint32_t datah =0;
uint32_t datal=0;
for(int i= 0; i<dlc;i++){
msgh=*data >> 4;
msgl=*data & 0x0f;
// printf("DATA %x%x",msgh,msgl);
memcpy(&datah, &msgh, 4);
memcpy(&datal, &msgl, 4);
// printf("msgl=%x\n",msgl);
data++;
}
printf("DATA%x%x",datah,datal);
}
No need to memcpying all this stuff – extracting the high and low nibbles of the bytes can be done as follows:
uint32_t high = 0;
uint32_t low = 0;
unsigned int offset = 0;
for(int i = 0; i < 8; ++i)
{
high |= ((uint32_t)(*data) >> 4) << offset;
low |= ((uint32_t)(*data) & 0x0f) << offset;
offset += 4;
++data;
}
Note how you need to shift the offsets such that the nibbles get at their right positions within their respective 32-bit values.
Note, too that this assumes little endian byte order of transferred data (the byte order must be known and fix as part of the protocol definition for communication!).
Big endian order slightly differs:
uint32_t high = 0;
uint32_t low = 0;
unsigned int offset = 32;
for(int i = 0; i < 8; ++i)
{
offset -= 4;
high |= (uint32_t)(*data >> 4) << offset;
low |= (uint32_t)(*data & 0x0f) << offset;
++data;
}
(Well, could have started with 28 as well and subtracted 4 after nibble extraction, analogously to LE variant – this variant reflects my personal preference for constants of powers of two – number of operations doesn't differ anyway…).
Finally note that you might prefer to separate conversion and outputting into separate functions to achieve better reusability, e.g. like
void extract(uint8_t const* data, uint32_t* high, uint32_t* low)
{
// assign to *high and *low analogously to above
}
// assuming C code; if C++, prefer references:
void extract(uint8_t const* data, uint32_t& high, uint32_t& low);
// or alternatively:
typedef struct
{
uint32_t high;
uint32-t low;
} NibblesCombined;
NibblesCombined extract(uint8_t const* data)
{
// assign to the members of the struct analogously to above
}
// again assuming C; C++ could optionally return a std::pair instead!
I'm reading the values from a SD card in an ARM micro:
Res = f_read(&fil, (void*)buf, 6, &NumBytesRead);
where fil is a pointer, buf is a buffer where the data is stored.
And that's the problem: it's an array but I'd like to have the contents of that array in a single variable.
To give an actual example: the 6 bytes read from the file are:
buf[0] = 0x1B
buf[1] = 0x26
buf[2] = 0xB3
buf[3] = 0x54
buf[4] = 0xA1
buf[5] = 0xCF
And I'd like to have: uint64_t data be equal to 0x1B26B354A1CF. That is, all the elements of the array "concatenated" in one single 64 bit integer.
Without type punning you can do as below.
uint64_t data = 0;
for (int i=0; i<6; i++)
{
data <<= 8;
data |= (uint64_t) buf[i];
}
Use union but remember about the endianes.
union
{
uint8_t u8[8];
uint64_t u64;
}u64;
typedef union
{
uint8_t u8[8];
uint64_t u64;
}u64;
typedef enum
{
LITTLE_E,
BIG_E,
}ENDIANESS;
ENDIANESS checkEndianess(void)
{
ENDIANESS result = BIG_E;
u64 d64 = {.u64 = 0xff};
if(d64.u8[0]) result = LITTLE_E;
return result;
}
uint64_t arrayToU64(uint8_t *array, ENDIANESS e) // for the array BE
{
u64 d64;
if(e == LITTLE_E)
{
memmove(&d64, array, sizeof(d64.u64));
}
else
{
for(int index = sizeof(d64.u64) - 1; index >= 0; index--)
{
d64.u8[sizeof(d64.u64) - index - 1] = array[index];
}
}
return d64.u64;
}
int main()
{
uint8_t BIG_E_Array[] = {0x10,0x20,0x30,0x40,0x50,0x60,0x70,0x80};
ENDIANESS e;
printf("This system endianess: %s\n", (e = checkEndianess()) == BIG_E ? "BIG":"LITTLE");
printf("Punned uint64_t for our system 0x%lx\n", arrayToU64(BIG_E_Array, e));
printf("Punned uint64_t for the opposite endianess system 0x%lx\n", arrayToU64(BIG_E_Array, e == BIG_E ? LITTLE_E : BIG_E));
return 0;
}
To things to take care of here:
have the bytes be ordered correctly
read the six bytes into one 64bit integer
Issue 1 can be taken care of by storing the byte coming in in network byte order (Big Endian) into the 64 bit integer in host byte order by for example using the two marcos below:
/* below defines of htonll() and ntohll() are taken from this answer:
https://stackoverflow.com/a/28592202/694576
*/
#if __BIG_ENDIAN__
# define htonll(x) (x)
# define ntohll(x) (x)
#else
# define htonll(x) ((uint64_t)htonl((x) & 0xFFFFFFFF) << 32) | htonl((x) >> 32))
# define ntohll(x) ((uint64_t)ntohl((x) & 0xFFFFFFFF) << 32) | ntohl((x) >> 32))
#endif
Issue 2 can be solved in multiple ways:
Extending your approach
#define BUFFER_SIZE (6)
...
assert(BUFFER_SIZE <= sizeof (uint64_t));
uint8_t buffer[BUFFER_SIZE];
FILE * pf = ...; /* open file here */
/* test if file has been opened successfully here */
... result = f_read(pf, buffer, BUFFER_SIZE, ...);
/* test result for success */
uint64_t number = 0;
memset(&number, buffer, BUFFER_SIZE)
number = ntohll(number);
Use "Type Punning" by using a union
union buffer_wrapper
{
uint8_t u8[sizeof (uint64_t)];
uint64_t u64;
}
Instead of
uint8_t buffer[BUFFER_SIZE];
use
union buffer_wrapper buffer;
and instead of
memcpy(&number, buffer, BUFFER_SIZE)
number = ntohll(number)
use
number = ntohll(buffer.u64)
I am new to c language and having some trouble in a program.I have 3 arrays
size = 8;
u8 a [size]; // a = 0x0D
u8 b [size]; // b= 0xDE
u16 new_buffer[size]; // i want to see as 0xDE0D on the terminal
I need to move the contents of a as Lower order byte and contents of b as higher order byte in the new_buffer and later right shift the the new_buffer by three bits. I read about it and was suggested to use two for loops. I tried it but not getting appropriate output.
please help me for this..
u8 SendBuffer[BUFFER_SIZE];
u8 RecvBuffer[BUFFER_SIZE];
u16 Buffer[BUFFER_SIZE];
int main(void) {
RecvBuffer[0] = 0x00;
RecvBuffer[1] = 0x0D;
if (Status != XST_SUCCESS) {
return XST_FAILURE;
}
printf("Sensor data is = 0x%x \n\r", RecvBuffer[0]);
printf("---Data received successfully---\n\r");
return 0;
}
Thanks
Two versions here, depending on the endian-ness
for (i=0; i<BUFFER_SIZE; i++) {
// little endian
new_buffer[i] = (u16)a[i] << 8 | (u16)b[i]);
// big endian
new_buffer[i] = (u16)b[i] << 8 | (u16)a[i]);
// bit shift
new_buffer[i] >>= 3;
}
Or, to rotate the buffer 3 bits to the right
u16 bits, prev = 0;
for (i=0; i<BUFFER_SIZE; i++) {
bits = new_buffer[i];
new_buffer[i] = bits >> 3 | prev;
prev = bits << (sizeof(u16)*8 - 3);
}
Note that u8 is not part of the standard, you mean uintX_t, and these values are not arrays but variables:
uint8_t a = 0X0D;
uint8_t b = 0XDE;
uint16_t new_buffer = ((uint16_t)b << 8) | a;
As pointed out by #WeatherVane, you need to reverse those values if you are under big endian:
uint16_t new_buffer = ((uint16_t)a << 8) | b;
I am trying to create a 48-bit integer value. I understand it may be possible to use a char array or struct, but I want to be able to do bit masking/manipulation and I'm not sure how that can be done.
Currently the program uses a 16-bit uint and I need to change it to 48. It is a bytecode interpreter and I want to expand the memory addressing to 4GB. I could just use 64-bit, but that would waste a lot of space.
Here is a sample of the code:
unsigned int program[] = { 0x1064, 0x11C8, 0x2201, 0x0000 };
void decode( )
{
instrNum = (program[i] & 0xF000) >> 12; //the instruction
reg1 = (program[i] & 0xF00 ) >> 8; //registers
reg2 = (program[i] & 0xF0 ) >> 4;
reg3 = (program[i] & 0xF );
imm = (program[i] & 0xFF ); //pointer to data
}
full program: http://en.wikibooks.org/wiki/Creating_a_Virtual_Machine/Register_VM_in_C
You can use the bit fields which are often used to represent integral types of known, fixed bit-width. A well-known usage of bit-fields is to represent a set of bits, and/or series of bits, known as flags. You can apply bit operations on them.
#include <stdio.h>
#include <stdint.h>
struct uint48 {
uint64_t x:48;
} __attribute__((packed));
Use a structure or uint16_t array with special functions for an array of uint48.
For individual instances, use uint64_t or unsigned long long. uint64_t will work fine for individually int48, but may want to mask off the results operations like * or << to keep upper bits cleared. Just some space saving routines are needed for arrays.
typedef uint64_t uint48;
const uint48 uint48mask = 0xFFFFFFFFFFFFFFFFull;
uint48 uint48_get(const uint48 *a48, size_t index) {
const uint16_t *a16 = (const uint16_t *) a48;
index *= 3;
return a16[index] | (uint32_t) a16[index + 1] << 16
| (uint64_t) a16[index + 2] << 32;
}
void uint48_set(uint48 *a48, size_t index, uint48 value) {
uint16_t *a16 = (uint16_t *) a48;
index *= 3;
a16[index] = (uint16_t) value;
a16[++index] = (uint16_t) (value >> 16);
a16[++index] = (uint16_t) (value >> 32);
}
uint48 *uint48_new(size_t n) {
size_t size = n * 3 * sizeof(uint16_t);
// Insure size allocated is a multiple of `sizeof(uint64_t)`
// Not fully certain this is needed - but doesn't hurt.
if (size % sizeof(uint64_t)) {
size += sizeof(uint64_t) - size % sizeof(uint64_t);
}
return malloc(size);
}
I was looking at hash functions the other day and came across a website that had an example of one. Most of the code was easy to grasp, however this macro function I can't really wrap my head around.
Could someone breakdown what's going on here?
#define get16bits(d) ((((uint32_t)(((const uint8_t *)(d))[1])) << 8) +(uint32_t)(((const uint8_t *)(d))[0]))
Basically it gets the lower 16 bit of the 32 bit integer d
lets break it down
#define get16bits(d) ((((uint32_t)(((const uint8_t *)(d))[1])) << 8) +(uint32_t)(((const uint8_t *)(d))[0]))
uint32_t a = 0x12345678;
uint16_t b = get16bits(&a); // b == 0x00005678
first we must pass the address of a to get16bits() or it will not work.
(((uint32_t)(const uint8_t *)(d))[1])) << 8
this first converts the 32 bit integer into an array of 8 bit integers and retrieves the 2 one.
It then shifts the value by 8 bit so it and adds the lower 8 bits to it
+ (uint32_t)(((const uint8_t *)(d))[0]))
In our example it will be
uint8_t tmp[4] = (uint8_t *)&a;
uint32_t result;
result = tmp[1] << 8; // 0x00005600
result += tmp[0]; //tmp[0] == 0x78
// result is now 0x00005678
The macro is more or less equivalent to:
static uint32_t get16bits(SOMETYPE *d)
{
unsigned char temp[ sizeof *d];
uint32_t val;
memcpy(temp, d, sizeof *d);
val = (temp[0] << 8)
+ temp[1];
return val;
}
, but the macro argument has no type, and the function argument does.
Another way would be to actually cast:
static uint32_t get16bits(SOMETYPE *d)
{
unsigned char *cp = (unsigned char*) d;
uint32_t val;
val = (cp[0] << 8)
+ cp[1];
return val;
}
, which also shows the weakness: by indexing with 1, the code assumes that sizeof (*d) is at least 2.