Question

I'm having a problem converting data.

I got a certain string (which actually represents just some bits of data (little endian), not a text):

char freeBlockSize[2];

and I want to convert it into this type:

unsigned short numOfBlocks;

I've been trying the following code, but it seems to print garbage, as everytime I run it I got a different output for the value of "numOFBlocks" (freeBlockSize is given to me by another function, and is always the same):

unsigned short numOFBlocks = (unsigned short)freeBlockSize;

printf("Test: %d %d\n",freeBlockSize[0],freeBlockSize[1]);
printf("Value: %hu\n",numOFBlocks);

Thank you in advance for your help.

Was it helpful?

Solution

Use:

  unsigned short numOFBlocks = *(unsigned short *)freeBlockSize;

But be careful: this will work if the endianess of the data you have in freeBlockSize is the same endianess of your machine, which could or could not be the case, depending on the source of the data stored in that vector.


UPDATE: There's a certain risk of accessing a misaligned pointer using this approach, so here you have another method that circunvent this issue:

unsigned short numOfBlocks = ((freeBlockSize[1] << 8) &0xFF00) | (freeBlockSize[0] & 0xFF);

This will take the 16-bit number pointed by freeBlockSize as a LE number, and will store it into numOfBlocks, in host endian format. The previous method wasn't take the host endian into account, and therefore it only worked if the data stored in freeBlockSize was in the same format as host data.

OTHER TIPS

If you want to be able to access the same memory as different values, a union would work.

union short_bytes {
    unsigned short shorty;
    char bytes[2];
};
...
union short_bytes foo;

foo.shorty = (unsigned short)freeBlockSize;

printf("Test: %hhd %hhd\n", foo.bytes[0], foo.bytes[1]);
printf("Value: %hu\n", foo.shorty);

After having a similar problem, I've discovered that char is a signed type. So to use a char type as numbers declare your variable or array as "unsigned char" then when you cast it to a longer type such as unsigned short, it will cast properly.

Let the compiler optimization take care of the details.

// OP says little endian.
#include <limits.h>
numOfBlocks = (unsigned char) freeBlockSize[1];
numOfBlocks <<= CHAR_BIT;  // thanks @Dietrich Epp 
numOfBlocks += (unsigned char) freeBlockSize[0];

Since OP now says little endian (which match network order) and endian-ness and portability is of concern, consider using after `*(unsigned short *)freeBlockSize``:

#include <netinet/in.h>
uint16_t htons(uint16_t hostshort);
uint16_t ntohs(uint16_t netshort);

Endianess issues aside, it's as simple as reinterpreting the memory holding the char[] array as holding a short:

char freeBlockSize[2];
unsigned short res;
// ..code..
res=*(unsigned short *)freeBlockSize;

By the way, assuming you're using some function and passing in the char[2] as a field inside a structure, you can just define the structure on your side as having the field an unsigned short instead (or an union of the two if you really need the 2 bytes explicitly). This would let you avoid the extra step.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top