简体   繁体   中英

Extract 2nd and 3rd value from char array and cast it as short (2 bytes). In C

Say I have an unsigned char (or byte) array. I want to take array[1] and array[2] from memory and cast it as short int (2 bytes). Something similar to how a union works, but not starting from the first byte.

Example:

#include <stdio.h>

void main()
{
    unsigned char a[28];
    unsigned short t;

    a[0]=12;
    a[1]=10;
    a[2]=55;

    t=(short) *(a+1);

    printf("%i", t);
}

What I want is the value 14090 in decimal. Or 370Ah.

Thank you.

EDIT: I forgot to say, but most of you understood from my example, I am working on a little-endian machine. An 8bit Atmel microcontroller.

It's very simple:

unsigned short t = (a[2] << 8) | a[1];

Note, this assumes unsigned char is 8 bits, which is most likely the case.

The memory access operation (short)*(a+1) is not safe.

If a+1 is not aligned to short (ie, a+1 is not a multiple of sizeof short ), then the result of this operation depends on the compiler at hand.

Compilers that support unaligned load/store operations can resolve it correctly, while others will "round it down" to the nearest address which is aligned to short .

In general, this operations yields undefined behavior.

On top of all that, even if you know for sure that a+1 is aligned to short , this operation will still give you different results between Big-Endian architecture and Little-Endian architecture.

Here is a safe way to work-around both issues:

short x = 0x1234;
switch (*(char*)&x)
{
    case 0x12: // Big-Endian
        t = (a[1] << 8) | a[2]; // Simulate t = (short)*(a+1) on BE
        break;
    case 0x34: // Little-Endian
        t = (a[2] << 8) | a[1]; // Simulate t = (short)*(a+1) on LE
        break;
}

Please note that the code above assumes the following:

  • CHAR_BIT == 8
  • sizeof short == 2

This is not necessarily true on every platform (although it is mostly the case).

t= *(short *)(a+1);

You cast the pointer to the first element to a pointer-to-short, and then dereference it.

Note that this is not very portable, and can go wrong if the machine is big endian or aligns data somehow. A better way would be:

t = (a[2] << CHAR_BIT) | a[1];

For full portability, you should check your endianness and see which byte to shift, and which one not to. See here how to check a machine's endianness

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM