Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Convert char to short

Tags:

c

char

short

I need to copy the data from 2 char (8 bit long) to a single short (16 bit long). I tried two different ways, but can't get it to work.

void char2short(char* pchar, short* pshort)
{
    memcpy(pshort    , pchar + 1    , 1);
    memcpy(pshort + 1, pchar    , 1);
}

And the other one:

void char2short(char* pchar, short* pshort)
{
   short aux;
   aux = ((*pchar & 0x00FF) << 8) | ((*(pchar+1) & 0xFF00) >> 8);
   *pshort = aux;
}
like image 624
ANIMATEK Avatar asked Sep 11 '14 12:09

ANIMATEK


4 Answers

#include <stdio.h>


void char2short(unsigned char* pchar, unsigned short* pshort)
{
  *pshort = (pchar[0] << 8) | pchar[1];
}

int main()
{
  unsigned char test[2];
  unsigned short result = 0;

  test[0] = 0xAB;
  test[1] = 0xCD;
  char2short(test, &result);
  printf("%#X\n",result);
  return 0;
}

this will do the job.

like image 64
mch Avatar answered Nov 17 '22 03:11

mch


Assuming pchar is an array that contains your 2 chars, how about:

*pshort = (uint16_t)(((unsigned int)pchar[0]) |
                    (((unsigned int)pchar[1])<<8));

P.S. This work for little endianess.

like image 23
n0p Avatar answered Nov 17 '22 01:11

n0p


Others didn't explain why your code didn't work, so I'll take a quick stab at it:

memcpy(pshort    , pchar + 1    , 1);
memcpy(pshort + 1, pchar    , 1);

Adding to a pointer TYPE * p moves the pointer by increments of sizeof( TYPE ) (so it does point at the next element, remember this is only defined if inside an array). So while pchar + 1 is correct, pshort + 1 is not (as it's addressing the next short).

aux = ((*pchar & 0x00FF) << 8) | ((*(pchar+1) & 0xFF00) >> 8);

Errr.... the right hand side is broken in more ways than one. First, *(pchar+1) is a char, and & 0xFF00 on a char will always yield 0 (because a char is only 8 bits to begin with, at least on contemporary machines...). And then you shift that 8 bits to the right...?

And just in case you weren't aware of it, if you hadn't used 0x00FF on the left hand side (promoting *pchar to the width of the right-hand operand) but (char-sized) 0xFF, the result of that operation would still be of type char, and shifting that 8 bits to the left doesn't make much sense either (as the type doesn't get expanded magically).


Another way to go about this not mentioned yet is the union:

 #include <stdio.h>

 struct chars_t
 {
     // could also go for char[2] here,
     // whichever makes more sense semantically...
     char first;
     char second;
 };

 union combo_t
 {
      // elements of a union share the memory, i.e.
      // reside at the same address, not consecutive ones
      short shrt;
      struct chars_t chrs;
 };

 int main()
 {
     union combo_t x;
     x.chrs.first = 0x01;
     x.chrs.second = 0x02;
     printf( "%x", x.shrt );
     return 0;
  }

If you're using this in a larger context, beware of struct padding.

like image 5
DevSolar Avatar answered Nov 17 '22 02:11

DevSolar


When doing bitwise operations, use robust code with real fixed-size integers, of known signedness. This will prevent you from writing bugs related to implicit type conversions, causing unintended signedness. The char type is particularly dangerous, since it has implementation-defined signedness. It should never be used for storing numbers.

#include <stdint.h>

void char2short(const uint8_t* pchar, uint16_t* pshort)
{
  *pshort = ((uint16_t)pchar[0] << 8) | (uint16_t)pchar[1];
}
like image 3
Lundin Avatar answered Nov 17 '22 02:11

Lundin