2 Chars to Short in C
Asked Answered
I

4

7

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?

Igniter answered 21/7, 2013 at 2:58 Comment(0)
R
5

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);
Rapp answered 5/8, 2018 at 15:14 Comment(1)
qalpha's answer is correct if you're using unsigned char. but for normal char, you'd need thisRapp
C
8

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];
}
Chabot answered 21/7, 2013 at 3:4 Comment(7)
With your modification, it's outputting 32770 instead of 640.Igniter
That would be up to the order that you have the two chars in. 32770 = 128 << 8 | 2, and 640 = 2 <<8 | 128. If you want it the other way, just switch the places of offset and offset + 1.Chabot
@qalpha What on earth... I have them in the correct order [128, 2] yet swapping the values worked. What's up with that?Igniter
I'd guess that it's to do with the [endianness]{en.wikipedia.org/wiki/Endianness} of your machine. It appears that the most significant byte is at the far left, and you were working as if the most significant byte is at the far right.Chabot
@qalpha Seems like my processor is Little-Endian. Was your method desgined for Big-Endian?Igniter
My method could be said to be for either endianness -- it just depends on which order the chars are stored in in the array. If the char that you want to be the most significant byte comes first, this works on little-endian processors, and if it comes last, it works on big-endian ones. Best practice would probably be to specify which order the chars are stored in, and then to make the code endianness-independent.Chabot
@qalpha Well, I'm sure that this is going to be run on a little-endian system, so I think I'm alright for now. Thanks!Igniter
R
5

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);
Rapp answered 5/8, 2018 at 15:14 Comment(1)
qalpha's answer is correct if you're using unsigned char. but for normal char, you'd need thisRapp
A
2

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
Abramson answered 21/7, 2013 at 7:26 Comment(1)
I like the Union method! Thanks for this answer.Igniter
P
0

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);
Patinated answered 21/7, 2013 at 3:44 Comment(2)
This seems like a really roundabout way to do things.Centeno
Yes I actually agree, but I was really stumped initially as to how SuperDisk was arriving at 640 from the values of 128 and 2. Convert 2 to hex, which is '2', convert 128 to hex, which is '80'. Slam them together and get the hex value '280', now convert that to a short. Bit shifting in all combinations did not produce 640.Patinated

© 2022 - 2024 — McMap. All rights reserved.