Typecasting with signed datatypes

I ran into some trouble with a piece of code. It is supposed to read a 16 bit signed integer over I2C. The data must be read in two 8 bit chars and then parsed together. Here is the code:

1
2
3
4
5
6
7
8
9
int ds1621_read(int sensor, int reg)
{
    unsigned char data[2];

    // Read data...

    return ((int)((short)data[1] + (((short)data[0]) << 8)));
}


The problem is that negative numbers loop around and become positive (i.e. -1 becomes 65535). I know that if I change the return line to:
return ((short)(data[1] + (((short)data[0]) << 8)));
then it works. I think the original turns a negative number into a positive number because it typecasts a 2 byte short into a 4 byte integer and the leading 2 bytes are filled with 0's rather than 1's, and without the leading 1's the int is interpreted as a positive number. My questions are these:

1) Is my assessment right, or did I just stumble across a solution?
2) Is it acceptable to return a short in a function that returns an int?

EDIT:

3) Why, in this case, does implicit typecasting work and explicit typecasting not?

Thanks in advance for any help.
Last edited on
It is because you are confusing the compiler on what is signed and what is unsigned. The fact that the change works is luck.

You need to be explicit:
1
2
3
4
5
6
7
8
int ds1621_read(int sensor, int reg)
{
    unsigned char data[2];

    // Read data...

    return (unsigned char)data[1] + ((signed char)data[0] << 8);
}

Notice how the low byte is left unsigned. (The cast is unnecessary there -- I just left it in to be explicit.)

The high byte, however, carries the sign bit. Hence, you must tell the compiler that it is signed (instead of what the compiler thinks it is [unsigned] based on line 3). The result would work just as well if you were to get the data with:
1
2
3
4
5
6
7
8
9
int ds1621_read(int sensor, int reg)
{
    unsigned char low_byte;
    signed char   high_byte;

    // Read data...

    return low_byte + (high_byte << 8);
}

This way, [edit] meaning: by being explicit as in both examples [/edit] the compiler does the appropriate type promotion (signed or unsigned) for each piece of the result.

Hope this helps.
Last edited on
Thanks, that makes perfect sense.
Topic archived. No new replies allowed.