Divide contents of a unsigned char array into 2 halves - c

I am wondering if anyone can help me I am only learning c, I am trying to Divide contents of a unsigned char array into 2 halves, which the result can stored in two unsigned int's,
For example purposes, I have some code below which adds a hex value into a BYTE array, so How would split the contents of val[] into two but keep the same order
#include <stdio.h>
typedef unsigned char BYTE;
int main()
{
// Sample purposes putting hex into val[8]
int i,j;
long long hex=0x78661EB54FE76763;
BYTE val[8];
for(j=0,i=7; i>=0; i--,j++){
val[j]= (hex>>(i*8))&0xff;
}
// How to split the contents of val[8] which now holds the hex
return 0;
}
I am trying to split the hex value into 78661EB5, 4FE76763 and store each one inside an unsigned int which is stored inside val[8] in my example

Your variable long long hex is not a "char array", but you can try something like this, notice unsigned types throughout.
#include <stdio.h>
#include <stdint.h>
int main(void)
{
uint64_t hex = 0x78661EB54FE76763;
uint32_t lo, hi;
hi = hex >> 32;
lo = hex & 0xFFFFFFFF;
printf("%08X %08X\n", hi, lo);
return 0;
}
Program output:
78661EB5 4FE76763

Create a helper function that takes a pointer to an array of unsigned char and call it twice.
Left some things out for OP to discover.
unsigned long form_big_endian4(const unsigned char * x) {
unsigned long y = TBB; // What should the initial value be?
for (int i = 0; i < TBD; i++) { // How many times to loop?
y *= TBD; // Hint: max value of 8 bits + 1
y += x[i];
}
return y;
}
#include <stdio.h>
int main(void) {
const unsigned char val[8] =
{ 0x78, 0x66, 0x1E, 0xB5, 0x4F, 0xE7, 0x67, 0x63 };
unsigned long half = form_big_endian4(val); // Why long: Hint how small can unsigned be?
printf("%08lX\n", half); // Why 0 in format? Why `lX`?
half = form_big_endian4(val + TBD); // How far an offset?
printf("%08lX\n", half);
return 0;
}

Related

How to copy hex representation of uint_64 to unsigned char array in hex, in C?

I'm not sure how to put what I am trying to achieve in words, but I'll just put an example below, hope you guys can lend me a hand!
Basically I'm trying to copy the hex representation of uint64_t value into an unsigned char array, in hex.
What I have:
uint64_t src;
unsigned char destination[8];
/* codes omitted, some codes that will change the value of src */
printf("src: %"PRIx64"\n", src); //this prints out src: 3132333435363738
How do I copy the values from src into destination array in a way that:
destination[0] = 0x31;
destination[1] = 0x32;
destination[2] = 0x33;
//and so on...
Thanks!
EDIT
I'm sorry If my question is unclear, I'm very new to programming and I'm struggling to explain myself.
Basically I'm just trying to store whatever that prints out from that printf() into the unsigned char array as hex.
e.g, printf() outputs a string of "3132333435363738", I want to take 31 and store it in dst[0] where the value of dst[0] will be 0x31, and so on, where dst[1] will be 0x32.
Please bear with me, thanks!
The easy and portable way to extract the bytes that make up an integer in a given order is to just use bit shifts (and possibly masks); in your case, you seem to want to extract your bytes in big-endian order (first byte in destination => most significant byte in src), so that would be:
uint64_t src;
unsigned char destination[8];
for(int i=0; i<8; ++i) {
destination[i] = src>>((7-i)*8);
}
At each iteration, src is shifted to the right by (7-i)*8 bits, because we want the desired byte to go "at the bottom" of the result
First iteration:
src = 0x123456789abcdef0;
i = 0
(7-i) = 7
src >> ((7-i)*8) = 0x12
so, we got 0x12 and we put it into destination[0]; at the next iteration, we have
i = 1
(7-i) = 6
src >> ((7-i)*8) = 0x1234
Now, we could mask the result with 0xFF to take only the bottom 8 bit (namely, 0x34), but that's not important in our case, since each element of destination is an unsigned byte, so when assigning a value larger than 255 (as in this case) it does unsigned overflow, which is well defined to take only the lower bytes that "fit" the target; so, destination[1]=0x34.
Repeat this for i up to 7 and you get the required result.
You can set a pointer to point to the uint64_t itself:
uint64_t src;
unsigned char *view;
view = (unsigned char *)&src;
for (size_t i = 0; i < sizeof(src); ++i) {
printf("%x", view[i]);
}
printf("\n");
If you need to copy the value, not just have another view of it, the same principle applies:
uint64_t src;
unsigned char dst[sizeof(src)];
memcpy((void *)&dst, (void *)&src, sizeof(src));
for (size_t i = 0; i < sizeof(src); ++i) {
printf("%x", dst[i]);
}
printf("\n");
Note that this will inherit the native endianness of the platform. If you want to convert endianness, you can use the library function uint64_t htobe64(uint64_t x) (Linux,BSD) or OSSwapHostToBigInt64(x) (OS X) on src before viewing/copying the string. I don't know the equivalents for Windows but I assume they have them. See I used unsigned char instead of char to avoid any sign extension issues.
Solutions using pointer casts + pointer arithmetic, or solutions using unions will not be portable.
Here is a simple way to do this portably, no matter endianess. There may be more effective ways.
#include <stdio.h>
#include <stdint.h>
#include <inttypes.h>
#include <stdbool.h>
int main(void)
{
uint64_t src;
uint8_t destination[8] = {0x31,0x32,0x33,0x34,0x35,0x36,0x37,0x38};
const uint16_t dummy = 1;
const bool is_little_endian = *(const uint8_t*)&dummy == 1;
src=0;
for(size_t i=0; i<8; i++)
{
size_t shift = i*8;
if(is_little_endian)
{
shift = 64-8-shift;
}
src |= (uint64_t)destination[i] << shift;
}
printf("%" PRIx64, src);
return 0;
}
This is essentially the same as the solution given by #Matteo Italia, but using a mask and an explicit cast to the fixed width type uint8_t instead of unsigned char. These solutions should work regardless of endianness, because the bitwise operators work on the value of the left operand, not its underlying representation.
#include <stdio.h>
#include <stdint.h>
#include <inttypes.h>
int main(void)
{
uint64_t src = 0x3132333435363738;
uint8_t destination[8];
uint64_t mask = 0xff << 56;
size_t i;
for (i = 0; i < 8; i++) {
destination[i] = (uint8_t) ((src & mask) >> (56 - i * 8));
mask >>= 8;
}
printf("src: 0x%" PRIx64 "\n", src);
for (i = 0; i < 8; i++) {
printf("destination[%zu] = 0x%" PRIx8 "\n", i, destination[i]);
}
return 0;
}
Output is:
src: 0x3132333435363738
destination[0] = 0x31
destination[1] = 0x32
destination[2] = 0x33
destination[3] = 0x34
destination[4] = 0x35
destination[5] = 0x36
destination[6] = 0x37
destination[7] = 0x38

unsigned char array of 8 bits to unsigned char

I've created a function that turns an unsigned char into an unsigned char array of size 8 (where each index contains either 0 or 1, making up the 8 bits of the given char). Here is the 100% working version:
unsigned char * ucharToBitArray(unsigned char c)
{
unsigned char * bits = malloc(8);
int i;
for(i=sizeof(unsigned char)*8; i; c>>=1)
bits[--i] = '0'+(c&1);
return bits ;
}
I need to create a function that does the exact opposite of this now. Meaning, it will take and unsigned char array of size 8, and turn it into a regular single unsigned char. What is an effective way of doing so?
Thanks for the help!
The function is needlessly complex and obscure. I would suggest replacing it with this:
void ucharToBitArray(char bits[8], uint8_t c)
{
for(uint8_t i=0; i<8; i++)
{
if(c & (1<<i))
{
bits[7-i] = '1';
}
else
{
bits[7-i] = '0';
}
}
}
Now to convert it back, simply go the other way around. Check bits[i] and then set c |= (1<<i) if you found a '1'.

How to convert byte array (containing hex values) to decimal

I am writing some code for an Atmel micro-controller. I am getting some data via Uart, and I store these hex values into an array.
Suppose the elements of the array are: 1F, 29, and 3C.
I want to have one hex number like 0x1F293C, and convert it to a decimal number. So, I want to get “2042172” at the end.
The array could have n elements, so I need a general solution.
Thank you.
sprintf(buffer, "%d", (((unsigned)array[0])<<16)+(((unsigned)array[1])<<8)+(unsigned)array[2];
this will write the hex values in array to buffer as readable string in decimal representation.
assuming sizeof(int)=4
If you have a array of characters like "0x1F293C" and want to convert it to int try this code:
char receivedByte[] = "0x1F293C";
char *p;
int intNumber = strtol(receivedByte, &p, 16);
printf("The received number is: %ld.\n", intNumber);
If data is declared as stated in the comments (char data[]={0x1F, 0x29, 0x3C}), you can run this program.
#include <stdio.h>
#include <stdlib.h>
int main()
{
char receivedByte[9], *p;
char data[] = { 0x1F, 0x29, 0x3C };
sprintf(receivedByte, "0x%X%X%X", data[0], data[1], data[2]);
int intNumber = strtol(receivedByte, &p, 16);
printf("The received number is: %ld.\n", intNumber);
return 0;
}
If the input consists of n bytes and are stored starting from a pointer array, you can add the values up in the order you "received" them - i.e., in the order they are written in the array.
unsigned int convertToDecimal (unsigned char *array, int n)
{
unsigned int result = 0;
while (n--)
{
result <<= 8;
result += *array;
array++;
}
return result;
}
Note that your sample input contains 3 bytes and you want a "general solution for n bytes", and so you may run out of space really fast. This function will only work for 0..4 bytes. If you need more bytes, you can switch to long long (8 bytes, currently).
For longer sequences than that you need to switch to a BigNum library.
#include <stdio.h>
int main(){
char data[] = {0x1F, 0x29, 0x3C};
int i, size = sizeof(data);
unsigned value = 0;
for(i=0;i<size;++i)
value = value * 256 + (unsigned char)data[i];
printf("0x%X %d\n", value, (int)value);
return 0;
}

Copying Ascii Value to int

I have code snippet as Below
unsigned char p = 0;
unsigned char t[4] = {'a','b','c','d'};
unsigned int m = 0;
for(p=0;p<4;p++)
{
m |= t[p];
printf("%c",m);
m = m << 2;
}
Can anybody help me in solving this. consider i have an ascii value abcd stored in an array t[]. I want to store the same value in 'm'. m is my unsigned int variable . which stores the major number. when i copy the array into m & print m . m should print abcd. can anybody state their logic.
As I understand you, you want to encode the 4 characters into a single int.
Your bit shifting is not correct. You need to shift by 8 bits rather than 2. You also need to perform the shifting before the bitwise or. Otherwise you shift too far.
And it makes more sense, in my view, to print the character rather than m.
#include <stdio.h>
int main(void)
{
const unsigned char t[4] = {'a','b','c','d'};
unsigned int m = 0;
for(int p=0;p<4;p++)
{
m = (m << 8) | t[p];
printf("%c", t[p]);
}
printf("\n%x", m);
return 0;
}
Why not just look at the t array as an unsigned int?:
unsigned int m = *(unsigned int*)t;
Or you could use an union for nice access to the same memory block in two different ways, which I think is better than shifting bits manually.
Below is an union example. With unions, both the t char array and the unsigned int are stored in the same memory blob. You get a nice interface to each, and it lets the compiler do the bit shifting (more portable, I guess):
#include <stdio.h>
typedef union {
unsigned char t[4];
unsigned int m;
} blob;
int main()
{
blob b;
b.t[0]='a';
b.t[1]='b';
b.t[2]='c';
b.t[3]='d';
unsigned int m=b.m; /* m holds the value of blob b */
printf("%u\n",m); /* this is the t array looked at as if it were an unsignd int */
unsigned int n=m; /* copy the unsigned int to another one */
blob c;
c.m=n; /* copy that to a different blob */
int i;
for(i=0;i<4;i++)
printf("%c\n",c.t[i]); /* even after copying it as an int, you can still look at it as a char array, if you put it into the blob union -- no manual bit manipulation*/
printf("%lu\n", sizeof(c)); /* the blob has the bytesize of an int */
return 0;
}
Simply assign t[p] to m.
m = t[p];
this will implicitly promote char to unsigned int.
unsigned char p = 0;
unsigned char t[4] = {'a','b','c','d'};
unsigned int m = 0;
for(p=0;p<4;p++)
{
m = t[p];
printf("%c",m);
}

conversion of BCD to unsigned char

I have a unsigned char array containing the following value : "\x00\x91\x12\x34\x56\x78\x90";
That is number being sent in Hexadecimal format.
Additionally, it is in BCD format : 00 in byte, 91 in another byte (8 bits)
On the other side I require to decode this value as 0091234567890.
I'm using the following code:
unsigned int conver_bcd(char *p,size_t length)
{
unsigned int convert =0;
while (length--)
{
convert = convert * 100 + (*p >> 4) * 10 + (*p & 15);
++p
}
return convert;
}
However, the result which I get is 1430637214.
What I understood was that I'm sending hexadecimal values (\x00\x91\x12\x34\x56\x78\x90) and my bcd conversion is acting upon the decimal values.
Can you please help me so that I can receive the output as 00911234567890 in Char
Regards
Karan
It looks like you are simply overflowing your unsigned int, which is presumably 32 bits on your system. Change:
unsigned int convert =0;
to:
uint64_t convert = 0;
in order to guarantee a 64 bit quantity for convert.
Make sure you add:
#include <stdint.h>
Cast char to unsigned char, then print it with %02x.
#include <stdio.h>
int main(void)
{
char array[] = "\x00\x91\x12\x34\x56\x78\x90";
int size = sizeof(array) - 1;
int i;
for(i = 0; i < size; i++){
printf("%02x", (unsigned char )array[i]);
}
return 0;
}
Change return type to unsigned long long to insure you have a large enough integer.
Change p type to an unsigned type.
Print value with leading zeros.
unsigned long long conver_bcd(const char *p, size_t length) {
const unsigned char *up = (const unsigned char*) p;
unsigned long long convert =0;
while (length--) {
convert = convert * 100 + (*up >> 4) * 10 + (*up & 15);
++up;
}
return convert;
}
const char *p = "\x00\x91\x12\x34\x56\x78\x90";
size_t length = 7;
printf( "%0*llu\n", (int) (length*2), conver_bcd(p, length));
// 00911234567890

Resources