c function to merge bytes - c

I have to write function in c to merge bytes from two unsigned int parameters,
taking the most significant byte of the second param and the rest of the first param.
For example if given x = 0x89ABCDEF and y = 0x76543210 so the function should return 0x76ABCDEF
now I know that char *c = (char*) &y will give me the MSB of y but then I don't know how to chain it to the rest of x without his MSB.
To be honest I completely forgot to do such simple thing in C as in last year all of my courses used Java, and I can't find it online, so any help would be appreciated.

This looks like a job for bit masking:
unsigned merge(unsigned x, unsigned y)
{
return (y & 0xFF000000) | (x & 0xFFFFFF);
}
Assuming 32-bit values, this used a bitwise AND to strip all but the top byte from y and only the top byte from x, then uses a bitwise OR to merge them togther.

If you want to support a known-length integer field using bitwise operators is the right choice, like others suggested. But I would answer your specific question using a char pointer this way:
unsigned int result;
char * rPtr = (char*) &result;
char * xPtr = (char*) &x;
*xPtr++;
*rPtr++ = *((char*)&y);
for(i = 1; i < sizeof(result); i++) {
*rPtr++ = *xPtr++;
}

Related

How to store the bit pattern of a 32 bit integer in a 32 length string of 0s and 1s in C

I'm trying to figure out how to do what I described in the title. However there are some rules. I can only use bit-level operations to determine whether a character is 0 or 1. So no function calls, macro invocations, addition, subtraction, division, modulus, or multiplication.
I most likely will wind up using XOR and/or bit shifting. I'm just unsure exactly how to go about it. I found a question on here someone asked that's similar but it involves converting from a string to an int. Any help is appreciated.
char *uintToChar(uint32_t uint, char *buff)
{
char *wptr = buff;
for(uint32_t i = 1ul << 31; i ; i >>= 1)
{
*wptr++ = (uint & i) ? '1' : '0';
}
*wptr = 0;
return buff;
}
int main(void)
{
char d[33];
printf("%s\n", uintToChar(0xf0f0f0f0, d));
}

C - fail to convert unsigned char array to double

I would like to convert a unsigned char array to double in C. I tried many way to do so but still wrongly converted to 0.00000.
union {
double longtitude;
unsigned char bytes[sizeof(double)];
}u;
unsigned char * receive_buffer = malloc(65536);
int recv = recv(fd,receive_buffer,65536,0);
// the buffer should has 8 byte value {40 5c 80 23 8d a3 c2 12}
memcpy(&u.bytes,receive_buffer,sizeof(double)); // copy to char array
for ( int i=8;i>=0;i--){
u.longtitude = u.bytes[i];
}
printf("%lf",u.longtitude); // the result is 0.000000 / the expected result should be 114.00217
I got the result of '0.000000' from above code that I found from internet. How can I convert the char array to double? What's wrong in above code?
UPDATE
I added more specific code above. I have checked the contents of the receive_buffer and it contains the value in the above comment. The u.bytes correctly gets a value from the buffer via memcpy. The union and for loop part is the way I found from other similar questions. I tried it, but got result = 0.000000. Sorry about the unclear code posted and problem stated before; I am quite new to C language.
Delete the for loop.
The memcpy copies the bytes from the buffer into the bytes array of the union. Those are the same bytes used for the longitude member, so they are already in place. You do not need the for loop to copy those bytes, and it was incorrectly writing the values of the bytes into the value of the double rather than into the bytes that represent the value. Also, the loop index was wrong, as it was using 8 in the first iteration, but the bytes in an eight-byte object are indexed 0 to 7.
More than that, in C, you can modify the bytes that repesent an object with either a union or a memcpy. You do not need both. After the recv, this suffices:
double longitude;
memcpy(&longitude, receive_buffer, sizeof longitude);
I expect you could even do the recv directly into &longitude.
Remove the for loop entirely. I'm not sure what your intent in having it there is, but it undoes (or rather just clobbers) the work you just did.
Based on your update and the expected value of 114.00217, the issue is endian-ness. Whatever machine you are getting the value from does not have the same endianess as your machine. So after converting to double, swap endianess.
// endian_swap() function taken from https://stackoverflow.com/a/21507710/669576
// I modified to work with double
double endian_swap(double d)
{
long x = *(long *)&d;
x = (x & 0x00000000FFFFFFFF) << 32 | (x & 0xFFFFFFFF00000000) >> 32;
x = (x & 0x0000FFFF0000FFFF) << 16 | (x & 0xFFFF0000FFFF0000) >> 16;
x = (x & 0x00FF00FF00FF00FF) << 8 | (x & 0xFF00FF00FF00FF00) >> 8;
return *(double *)&x;
}
int main(void) {
unsigned char s[] = {0x40,0x5c,0x80,0x23,0x8d,0xa3,0xc2,0x12};
double d;
// Just copy - no union needed
memcpy(&d, s, sizeof(d));
// Swap endianess
d = endian_swap(d);
printf("%lf\n", d);
return 0;
}
Output: 114.002170
I don't do a lot of network programming, but I believe the ntohl() function is used for this. However, I don't know if there is a 64-bit version.
Update: Also, you can use htobe64() (Thanks to #Stargateur):
#include <endian.h>
int main(void) {
unsigned char s[] = {0x40,0x5c,0x80,0x23,0x8d,0xa3,0xc2,0x12};
// htobe64() expects a long, so use that first
long l;
memcpy(&l, s, sizeof(l));
l = htobe64(l);
// Then copy the swapped long bits to a double
double d;
memcpy(&d, &l, sizeof(d));
printf("%lf\n", d);
return 0;
}

sprintf to convert hexadecimal array to decimal char array only reads first byte

I have an array:
unsigned char datalog[4];
datalog[0] = 0;
datalog[1] = 0xce;
datalog[2] = 0x50;
datalog[3] = 0xa3;
These represent the hex value 0xce50a3. Its decimal value is 13521059.
I need to convert this hex value to a decimal array, preferably using sprintf, so that the final outcome will be:
finalarray[0] = '1';
finalarray[1] = '3';
finalarray[2] = '5';
finalarray[3] = '2';
finalarray[4] = '1';
finalarray[5] = '0';
finalarray[6] = '5';
finalarray[7] = '9';
I've tried several combinations of sprintf inputs, including concatenating my hex array into unsigned long datalogvalue = 0xce50a3. But sprintf only reads its first byte when it converts.
ex:
sprintf(finalarray, "%d", *(unsigned long *)datalog);
yields:
finalarray[0] = '2';
finalarray[1] = '0';
finalarray[2] = '6';
finalarray[3] = ' ';
.....
206 is the decimal representation of 0xce. So it's only converting the first hex byte and not the rest.
Any thoughts on how to convert the entire unsigned long into a decimal array?
As some others have mentioned, attempting to read the bytes of an array in order as a number will be system-dependent as Big Endian and Little Endian systems will give different results.
Furthermore, type-punning through pointer-trickery is undefined behavior as it breaks strict aliasing. The legal way to type pun to a type other than a char-family array involves using unions to represent the data in more than one fashion. Due to the above Endian issue, though, you should not do that for this problem and instead do the bit-shifting method as mentioned in R Sahu's answer.
A simply solution that does not depend on endian, int sizes or pointer tricks
Form the value
// LU to use unsigned long math
((datalog[0]*256LU + datalog[1])*256 + datalog[2])*256 + datalog[3]
Print it
sprintf(finalarray, "%lu", value);
Altogether
sprintf(finalarray, "%lu",
((datalog[0]*256LU + datalog[1])*256 + datalog[2])*256 + datalog[3]);
The outcome of casting a char* to unsigned long* and dereferencing that pointer depends on the endianness of your system. Unless efficiency of this particular calculation is critical for performance of your program, don't use such tricks. Use simple logic.
int res = (datalog[0] << 24) +
(datalog[1] << 16) +
(datalog[2] << 8) +
datalog[3];
sprintf(finalarray, "%d", res);
If you are required to use unsigned long for your type, make sure to use the right format specifier for unsigned long in the call to sprintf.
unsigned long res = (datalog[0] << 24) +
(datalog[1] << 16) +
(datalog[2] << 8) +
datalog[3];
sprintf(finalarray, "%lu", res);
First and foremost, endianness makes things abit troublesome here.
In order to be able to reinterpret your buffer as a 32 bit int you would have to take endianness into consideration when packing.
For example, on my system which is little-endian, datalog would be interpreted as: 2739981824 if converted to a 32 bit unsigned int.
Hence I would have to pack my data according to datalog2 in the example below in order to get the desired 13521059.
#include <stdlib.h>
#include <stdio.h>
#include <stdint.h>
int main() {
uint8_t datalog[4];
datalog[0] = 0;
datalog[1] = 0xce;
datalog[2] = 0x50;
datalog[3] = 0xa3;
uint32_t temp = *((uint32_t*) datalog);
printf("%u\n", temp); // 2739981824
uint8_t datalog2[4];
datalog2[0] = 0xa3;
datalog2[1] = 0x50;
datalog2[2] = 0xce;
datalog2[3] = 0;
uint32_t temp2 = *((uint32_t*) datalog2);
printf("%u\n", temp2); // 13521059
return 0;
}
There is however another problem with what you are asking.
If I interpret your question correctly, you would like to end up with another array where each of the decimals making up 13521059 in base-10, ends up in its own index.
In order to do this you would have to be able to address log2(10) bits with each index, something that is impossible.
Therefore in order to get an array with the packing that you suggest, you would have to manually convert it.
Due to endianess, the bytes do not appear in the order you think they do:
IDEOne Link
#include <stdio.h>
int main(void) {
unsigned char datalog[4];
char finalarray[20] = {0};
datalog[0] = 0xa3;
datalog[1] = 0x50;
datalog[2] = 0xce;
datalog[3] = 0x00;
sprintf(finalarray, "%lu", *(unsigned long*)datalog);
printf("Answer: %s\n", finalarray);
return 0;
}
Output
Success #stdin #stdout 0s 4180KB
Answer: 13521059

Bit Rotation in C

The Problem: Exercise 2-8 of The C Programming Language, "Write a function rightrot(x,n) that returns the value of the integer x, rotated to the right by n positions."
I have done this every way that I know how. Here is the issue that I am having. Take a given number for this exercise, say 29, and rotate it right one position.
11101 and it becomes 11110 or 30. Let's say for the sake of argument that the system we are working on has an unsigned integer type size of 32 bits. Let's further say that we have the number 29 stored in an unsigned integer variable. In memory the number will have 27 zeros ahead of it. So when we rotate 29 right one using one of several algorithms mine is posted below, we get the number 2147483662. This is obviously not the desired result.
unsigned int rightrot(unsigned x, int n) {
return (x >> n) | (x << (sizeof(x) * CHAR_BIT) - n);
}
Technically, this is correct, but I was thinking that the 27 zeros that are in front of 11101 were insignificant. I have also tried a couple of other solutions:
int wordsize(void) { // compute the wordsize on a given machine...
unsigned x = ~0;
int b;
for(b = 0; x; b++)
x &= x-1;
return x;
}
unsigned int rightrot(unsigned x, int n) {
unsigned rbit;
while(n --) {
rbit = x >> 1;
x |= (rbit << wordsize() - 1);
}
return x;
This last and final solution is the one where I thought that I had it, I will explain where it failed once I get to the end. I am sure that you will see my mistake...
int bitcount(unsigned x) {
int b;
for(b = 0; x; b++)
x &= x-1;
return b;
}
unsigned int rightrot(unsigned x, int n) {
unsigned rbit;
int shift = bitcount(x);
while(n--) {
rbit = x & 1;
x >>= 1;
x |= (rbit << shift);
}
}
This solution gives the expected answer of 30 that I was looking for, but if you use a number for x like oh say 31 (11111), then there are issues, specifically the outcome is 47, using one for n. I did not think of this earlier, but if a number like 8 (1000) is used then mayhem. There is only one set bit in 8, so the shift is most certainly going to be wrong. My theory at this point is that the first two solutions are correct (mostly) and I am just missing something...
A bitwise rotation is always necessarily within an integer of a given width. In this case, as you're assuming a 32-bit integer, 2147483662 (0b10000000000000000000000000001110) is indeed the correct answer; you aren't doing anything wrong!
0b11110 would not be considered the correct result by any reasonable definition, as continuing to rotate it right using the same definition would never give you back the original input. (Consider that another right rotation would give 0b1111, and continuing to rotate that would have no effect.)
In my opinion, the spirit of the section of the book which immediately precedes this exercise would have the reader do this problem without knowing anything about the size (in bits) of integers, or any other type. The examples in the section do not require that information; I don't believe the exercises should either.
Regardless of my belief, the book had not yet introduced the sizeof operator by section 2.9, so the only way to figure the size of a type is to count the bits "by hand".
But we don't need to bother with all that. We can do bit rotation in n steps, regardless of how many bits there are in the data type, by rotating one bit at a time.
Using only the parts of the language that are covered by the book up to section 2.9, here's my implementation (with integer parameters, returning an integer, as specified by the exercise): Loop n times, x >> 1 each iteration; if the old low bit of x was 1, set the new high bit.
int rightrot(int x, int n) {
int lowbit;
while (n-- > 0) {
lowbit = x & 1; /* save low bit */
x = (x >> 1) & (~0u >> 1); /* shift right by one, and clear the high bit (in case of sign extension) */
if (lowbit)
x = x | ~(~0u >> 1); /* set the high bit if the low bit was set */
}
return x;
}
You could find the location of the first '1' in the 32-bit value using binary search. Then note the bit in the LSB location, right shift the value by the required number of places, and put the LSB bit in the location of the first '1'.
int bitcount(unsigned x) {
int b;
for(b = 0; x; b++)
x &= x-1;
return b;
}
unsigned rightrot(unsigned x,int n) {
int b = bitcount(x);
unsigned a = (x&~(~0<<n))<<(b-n+1);
x>> = n;
x| = a;
}

How to convert from integer to unsigned char in C, given integers larger than 256?

As part of my CS course I've been given some functions to use. One of these functions takes a pointer to unsigned chars to write some data to a file (I have to use this function, so I can't just make my own purpose built function that works differently BTW). I need to write an array of integers whose values can be up to 4095 using this function (that only takes unsigned chars).
However am I right in thinking that an unsigned char can only have a max value of 256 because it is 1 byte long? I therefore need to use 4 unsigned chars for every integer? But casting doesn't seem to work with larger values for the integer. Does anyone have any idea how best to convert an array of integers to unsigned chars?
Usually an unsigned char holds 8 bits, with a max value of 255. If you want to know this for your particular compiler, print out CHAR_BIT and UCHAR_MAX from <limits.h> You could extract the individual bytes of a 32 bit int,
#include <stdint.h>
void
pack32(uint32_t val,uint8_t *dest)
{
dest[0] = (val & 0xff000000) >> 24;
dest[1] = (val & 0x00ff0000) >> 16;
dest[2] = (val & 0x0000ff00) >> 8;
dest[3] = (val & 0x000000ff) ;
}
uint32_t
unpack32(uint8_t *src)
{
uint32_t val;
val = src[0] << 24;
val |= src[1] << 16;
val |= src[2] << 8;
val |= src[3] ;
return val;
}
Unsigned char generally has a value of 1 byte, therefore you can decompose any other type to an array of unsigned chars (eg. for a 4 byte int you can use an array of 4 unsigned chars). Your exercise is probably about generics. You should write the file as a binary file using the fwrite() function, and just write byte after byte in the file.
The following example should write a number (of any data type) to the file. I am not sure if it works since you are forcing the cast to unsigned char * instead of void *.
int homework(unsigned char *foo, size_t size)
{
int i;
// open file for binary writing
FILE *f = fopen("work.txt", "wb");
if(f == NULL)
return 1;
// should write byte by byte the data to the file
fwrite(foo+i, sizeof(char), size, f);
fclose(f);
return 0;
}
I hope the given example at least gives you a starting point.
Yes, you're right; a char/byte only allows up to 8 distinct bits, so that is 2^8 distinct numbers, which is zero to 2^8 - 1, or zero to 255. Do something like this to get the bytes:
int x = 0;
char* p = (char*)&x;
for (int i = 0; i < sizeof(x); i++)
{
//Do something with p[i]
}
(This isn't officially C because of the order of declaration but whatever... it's more readable. :) )
Do note that this code may not be portable, since it depends on the processor's internal storage of an int.
If you have to write an array of integers then just convert the array into a pointer to char then run through the array.
int main()
{
int data[] = { 1, 2, 3, 4 ,5 };
size_t size = sizeof(data)/sizeof(data[0]); // Number of integers.
unsigned char* out = (unsigned char*)data;
for(size_t loop =0; loop < (size * sizeof(int)); ++loop)
{
MyProfSuperWrite(out + loop); // Write 1 unsigned char
}
}
Now people have mentioned that 4096 will fit in less bits than a normal integer. Probably true. Thus you can save space and not write out the top bits of each integer. Personally I think this is not worth the effort. The extra code to write the value and processes the incoming data is not worth the savings you would get (Maybe if the data was the size of the library of congress). Rule one do as little work as possible (its easier to maintain). Rule two optimize if asked (but ask why first). You may save space but it will cost in processing time and maintenance costs.
The part of the assignment of: integers whose values can be up to 4095 using this function (that only takes unsigned chars should be giving you a huge hint. 4095 unsigned is 12 bits.
You can store the 12 bits in a 16 bit short, but that is somewhat wasteful of space -- you are only using 12 of 16 bits of the short. Since you are dealing with more than 1 byte in the conversion of characters, you may need to deal with endianess of the result. Easiest.
You could also do a bit field or some packed binary structure if you are concerned about space. More work.
It sounds like what you really want to do is call sprintf to get a string representation of your integers. This is a standard way to convert from a numeric type to its string representation. Something like the following might get you started:
char num[5]; // Room for 4095
// Array is the array of integers, and arrayLen is its length
for (i = 0; i < arrayLen; i++)
{
sprintf (num, "%d", array[i]);
// Call your function that expects a pointer to chars
printfunc (num);
}
Without information on the function you are directed to use regarding its arguments, return value and semantics (i.e. the definition of its behaviour) it is hard to answer. One possibility is:
Given:
void theFunction(unsigned char* data, int size);
then
int array[SIZE_OF_ARRAY];
theFunction((insigned char*)array, sizeof(array));
or
theFunction((insigned char*)array, SIZE_OF_ARRAY * sizeof(*array));
or
theFunction((insigned char*)array, SIZE_OF_ARRAY * sizeof(int));
All of which will pass all of the data to theFunction(), but whether than makes any sense will depend on what theFunction() does.

Resources