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;
}
Related
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++;
}
I was wondering if I could use a char* value to access to each byte of an int value... So I tried to use a pointer value to access the first byte of the int and a for cycle to access the other bytes of int...
Here's the code:
int char_to_bin(char* d){
int p= (int)*d;
int i=0,number=0;
if (p>=0){
do{
number+= (p%2)*(pow(10,i));
i++;
p= p/2;
}while (p>0);
}
else{
p=p *(-1);
do{
number+= (p%2)*pow(10,i);
i++;
p=p/2;
}while (p>0);
number*=-1;
}
return number;
}
long int int_to_bin(int* p){
long int j=1,number=0,number1=0,number2=0,digits;
char* c=&p;
number=char_to_bin(c);
for (j;j<(sizeof(int)/sizeof(char));j++){
number1=char_to_bin(c+j);
digits=floor(log10(abs(number1))) + 1;
number2=number1*pow(10,digits);
number=number1+number2;
}
return number;
}
int main(){
char k= 100;
char* j= &k;
int inte=100;
int *h;
h= &inte;
int c= char_to_bin(j);
printf("%d\n",c);
long int d= int_to_bin(h);
printf("%ld\n",d);
}
the function int char_to_bin(char* d) converts a pointed char value to a binary number, and all the tests I've done on it show it works. But as I use int char_to_bin(char* d) in int_to_bin(int* p) something goes wrong.
Basically, int_to_bin(int* p) should convert the first byte of the pointed int in binary, and then convert the following bytes (since char* points at one only byte) to decimal, multiply the bytes for 10^(number of digits), so that I might get a number like "000000001100100" for example but something goes wrong and the result of the function is far different from binary, plus, i have tried to put a printf("%d \n",number1) in the int_to_bin(int* p) function, like this:
long int int_to_bin(int* p){
long int j=1,number=0,number1=0,number2=0,digits;
char* c=&p;
number=char_to_bin(c);
for (j;j<(sizeof(int)/sizeof(char));j++){
number1=char_to_bin(c+j);
printf("%d \n",number1); //---------------here------------------
digits=floor(log10(abs(number1))) + 1;
number2=number1*pow(10,digits);
number=number1+number2;
}
return number;
}
to check the value contained in the given memory address... As far as I know, int variable types occupy 4 bytes of memory, and the sum of the content of the bytes is the value or the variable... But I get results that summed are totally different from the variable value.
Is there anything to be done to fix this, or should I just give up and try to convert the int passed int_to_bin(int* p) into char and pass it to the char_to_bin(char* p) function?
As far as I know, int variable types occupy 4 bytes of memory, and the
sum of the content of the bytes is the value or the variable...
Well, int is sizeof(int) bytes, which is usually 4 on modern PC operating systems (both 64 and 32 bit), but it can be anything as long as sizeof(short) <= sizeof(int) <= sizeof(long). So always use sizeof instead of hard-coded value.
But value is not sum of contents... That would be very wasteful, same bytes in different order would give same int. Value is, depending on byte order, and assuming unsigned numbers:
(c[0] << 24) | (c[1] << 16) | (c[2] << 8) | (c[3] << 0); // big endian
or
(c[3] << 24) | (c[2] << 16) | (c[1] << 8) | (c[0] << 0); // little endian
where unsigned char *c = (unsigned char*)(&unsigned_int_variable);.
Note that even though char* pointers are exception (see comments), generally setting pointers of different types to point to values breaks so called "strict aliasing rules", which you should read about before doing this kind of thing.
I've got 2 chars.
Char 128 and Char 2.
How do I turn these chars into the Short 640 in C?
I've tried
unsigned short getShort(unsigned char* array, int offset)
{
short returnVal;
char* a = slice(array, offset, offset+2);
memcpy(&returnVal, a, 2);
free(a);
return returnVal;
}
But that didn't work, it just displays it as 128. What's the preferred method?
Probably the easiest way to turn two chars, a and b, into a short c, is as follows:
short c = (((short)a) << 8) | b;
To fit this into what you have, the easiest way is probably something like this:
unsigned short getShort(unsigned char* array, int offset)
{
return (short)(((short)array[offset]) << 8) | array[offset + 1];
}
I found that the accepted answer was nearly correct, except i'd run into a bug where sometimes the top byte of the result would be 0xff...
I realized this was because of C sign extension. if the second char is >= 0x80, then converting 0x80 to a short becomes 0xff80. Performing an 'or' of 0xff80 with anything results in the top byte remaining 0xff.
The following solution avoids the issue by zeroing out the top byte of b during its implicit conversion to a short.
short c = (((short)a) << 8) | (0x00ff & b);
I see that there is already an answer, but I'm a bit puzzled about what was going on with your original attempt. The following code shows your way and a technique using a union. Both seem to work just fine. I suppose you might have been running into an endianness problem. Anyway, perhaps this demonstration will be useful even if your problem is already solved.
#include <stdio.h>
#include <string.h>
int main()
{
short returnVal;
char a[2];
union {
char ch[2];
short n;
} char2short;
a[0] = 128;
a[1] = 2;
memcpy(&returnVal, a, 2);
printf("short = %d\n", returnVal);
char2short.ch[0] = 128;
char2short.ch[1] = 2;
printf("short (union) = %d\n", char2short.n);
return 0;
}
Outputs:
short = 640
short (union) = 640
I see that you are not actually trying to shift bits but assemble the equivelant of hex values together, like you would color values in CSS.
Give this code a shot:
char b1=128,b2=2;
char data[16];
sprintf((char *)data,"%x%x",(BYTE)b2,(BYTE)b1);
short result=strtol(data,(char **)NULL, 16);
I have an unsigned int number (2 byte) and I want to convert it to unsigned char type. From my search, I find that most people recommend to do the following:
unsigned int x;
...
unsigned char ch = (unsigned char)x;
Is the right approach? I ask because unsigned char is 1 byte and we casted from 2 byte data to 1 byte.
To prevent any data loss, I want to create an array of unsigned char[] and save the individual bytes into the array. I am stuck at the following:
unsigned char ch[2];
unsigned int num = 272;
for(i=0; i<2; i++){
// how should the individual bytes from num be saved in ch[0] and ch[1] ??
}
Also, how would we convert the unsigned char[2] back to unsigned int.
Thanks a lot.
You can use memcpy in that case:
memcpy(ch, (char*)&num, 2); /* although sizeof(int) would be better */
Also, how would be convert the unsigned char[2] back to unsigned int.
The same way, just reverse the arguments of memcpy.
How about:
ch[0] = num & 0xFF;
ch[1] = (num >> 8) & 0xFF;
The converse operation is left as an exercise.
How about using a union?
union {
unsigned int num;
unsigned char ch[2];
} theValue;
theValue.num = 272;
printf("The two bytes: %d and %d\n", theValue.ch[0], theValue.ch[1]);
It really depends on your goal: why do you want to convert this to an unsigned char? Depending on the answer to that there are a few different ways to do this:
Truncate: This is what was recomended. If you are just trying to squeeze data into a function which requires an unsigned char, simply cast uchar ch = (uchar)x (but, of course, beware of what happens if your int is too big).
Specific endian: Use this when your destination requires a specific format. Usually networking code likes everything converted to big endian arrays of chars:
int n = sizeof x;
for(int y=0; n-->0; y++)
ch[y] = (x>>(n*8))&0xff;
will does that.
Machine endian. Use this when there is no endianness requirement, and the data will only occur on one machine. The order of the array will change across different architectures. People usually take care of this with unions:
union {int x; char ch[sizeof (int)];} u;
u.x = 0xf00
//use u.ch
with memcpy:
uchar ch[sizeof(int)];
memcpy(&ch, &x, sizeof x);
or with the ever-dangerous simple casting (which is undefined behavior, and crashes on numerous systems):
char *ch = (unsigned char *)&x;
Of course, array of chars large enough to contain a larger value has to be exactly as big as this value itself.
So you can simply pretend that this larger value already is an array of chars:
unsigned int x = 12345678;//well, it should be just 1234.
unsigned char* pChars;
pChars = (unsigned char*) &x;
pChars[0];//one byte is here
pChars[1];//another byte here
(Once you understand what's going on, it can be done without any variables, all just casting)
You just need to extract those bytes using bitwise & operator. OxFF is a hexadecimal mask to extract one byte. Please look at various bit operations here - http://www.catonmat.net/blog/low-level-bit-hacks-you-absolutely-must-know/
An example program is as follows:
#include <stdio.h>
int main()
{
unsigned int i = 0x1122;
unsigned char c[2];
c[0] = i & 0xFF;
c[1] = (i>>8) & 0xFF;
printf("c[0] = %x \n", c[0]);
printf("c[1] = %x \n", c[1]);
printf("i = %x \n", i);
return 0;
}
Output:
$ gcc 1.c
$ ./a.out
c[0] = 22
c[1] = 11
i = 1122
$
Endorsing #abelenky suggestion, using an union would be a more fail proof way of doing this.
union unsigned_number {
unsigned int value; // An int is 4 bytes long
unsigned char index[4]; // A char is 1 byte long
};
The characteristics of this type is that the compiler will allocate memory only for the biggest member of our data structure unsigned_number, which in this case is going to be 4 bytes - since both members (value and index) have the same size. Had you defined it as a struct instead, we would have 8 bytes allocated on memory, since the compiler does its allocation for all the members of a struct.
Additionally, and here is where your problem is solved, the members of an union data structure all share the same memory location, which means they all refer to same data - think of that like a hard link on GNU/Linux systems.
So we would have:
union unsigned_number my_number;
// Assigning decimal value 202050300 to my_number
// which is represented as 0xC0B0AFC in hex format
my_number.value = 0xC0B0AFC; // Representation: Binary - Decimal
// Byte 3: 00001100 - 12
// Byte 2: 00001011 - 11
// Byte 1: 00001010 - 10
// Byte 0: 11111100 - 252
// Printing out my_number one byte at time
for (int i = 0; i < (sizeof(my_number.value)); i++)
{
printf("index[%d]: %u, 0x%x\n", \
i, my_number.index[i], my_number.index[i]);
}
// Printing out my_number as an unsigned integer
printf("my_number.value: %u, 0x%x", my_number.value, my_number.value);
And the output is going to be:
index[0]: 252, 0xfc
index[1]: 10, 0xa
index[2]: 11, 0xb
index[3]: 12, 0xc
my_number.value: 202050300, 0xc0b0afc
And as for your final question, we wouldn't have to convert from unsigned char back to unsigned int since the values are already there. You just have to choose by which way you want to access it
Note 1: I am using an integer of 4 bytes in order to ease the understanding of the concept. For the problem you presented you must use:
union unsigned_number {
unsigned short int value; // A short int is 2 bytes long
unsigned char index[2]; // A char is 1 byte long
};
Note 2: I have assigned byte 0 to 252 in order to point out the unsigned characteristic of our index field. Was it declared as a signed char, we would have index[0]: -4, 0xfc as output.
These are my two variables with which I want to do an xor operation (in C).
unsigned long int z=0xB51A06CD;
unsigned char array[] = {0xF0,0xCC,0xAA,0xF0};
desired output= 0X45D6AC3D
I know I cannot do a simple z ^ array, because it's a character array and not a single character. Will I have to do XOR of one byte at a time or is there a function for it in C?
I am trying all kinds of crazy things to get it done, but failing miserably all the time. If anyone can help me out with a small code snippet or at least a rough idea, I would be extremely grateful.
Cast the array, which is treat as a pointer to the first element in an expression like this one, to a long pointer instead of char pointer , and dereference it.
unsigned long result = z ^ *(unsigned long *)array;
Just make an unsigned long int out of your array (warning, it depends on the machine endianness!):
unsigned long int z=0xB51A06CD;
unsigned char array[] = {0xF0,0xCC,0xAA,0xF0};
unsigned long int w = 0;
w |= array[0] << 0;
w |= array[1] << 8;
w |= array[2] << 16;
w |= array[3] << 24;
unsigned long output = z ^ w;
unsigned long int z=0xB51A06CD;
unsigned char array[] = {0xF0,0xCC,0xAA,0xF0};
unsigned long tmp;
memcpy(&tmp, array, sizeof tmp);
... z ^ tmp ...
Note that this still makes a number of non-portable assumptions: that unsigned long is 4 bytes, and that the system's endianness is what you expect it to be.
As others mentioned, you have to worry about endianness and size of long. Here's how to make it safe:
1) instead of unsigned long, use uint32_t (from inttypes.h), to be sure you get a 4 byte type.
2) use htonl() as a platform-independent way to ensure you interpret the array as a big-endian value
z ^ htonl(*(uint32_t *)array);