Re: A portable code to create a 4-bytes Big Endian twos complement signed integer in a misaligned ad

Discussion in 'C Programming' started by Tim Rentsch, Mar 19, 2011.

  1. Tim Rentsch

    Tim Rentsch Guest

    pozz <> writes:

    > I need a variable that can represents numbers between -100000 and
    > +100000. int variables could be only 16-bit on some implementations,
    > so I use int32_t type:
    > int32_t x;
    > Is it correct?
    >
    > Now I need to create a data packet (to send over a network) with the
    > following syntax:
    > - Byte 1: SOP (Start of Packet)
    > - Byte 2-3-4-5: value in Big Endian twos complement
    > - Byte 6: EOP (End of Packet)
    >
    > How can I do that in the most portable way, assuming only the same
    > method to store negative numbers in memory (twos complement)?
    >
    > One solution could be:
    > unsigned char data[6] = { SOP, 0, 0, 0, 0, EOP };
    > data[1] = (x >> 24) & 0xFF;
    > data[2] = (x >> 16) & 0xFF;
    > data[3] = (x >> 8) & 0xFF;
    > data[4] = (x >> 0) & 0xFF;
    > This code should work with Big- or Little-Endian implementations.
    >
    > Or is it better to use htons()/htonl()?
    > int32_t tmp;
    > unsigned char data[6] = { SOP, 0, 0, 0, 0, EOP };
    > tmp = htonl(x);
    > memcpy (&data[1], &tmp, 4);
    > Should I use htonl() or htons()? I think on some architecture htons()
    > could be sufficient (short int are 32-bits), on others I need htonl
    > (short int are 16-bits).
    >
    > And what can I do if I need a packet with a 3-byte signed integer,
    > like the following:
    > - Byte 1: SOP (Start of Packet)
    > - Byte 2-3-4: value in Big Endian twos complement
    > - Byte 5: EOP (End of Packet)


    I suggest these (suitably documented, of course):

    unsigned char *
    store_as_four_octets_high_to_low( void *where, long what ){
    unsigned char *result = where;
    unsigned long v = what;

    result[0] = v>>24 & 0xFF;
    result[1] = v>>16 & 0xFF;
    result[2] = v>>8 & 0xFF;
    result[3] = v>>0 & 0xFF;

    return result;
    }

    Hint: in the three octet version, the assignment statements
    need to be revised/condensed.


    long
    read_as_four_octets_high_to_low( void *where ){
    unsigned char *w = where;
    unsigned long v;
    const unsigned long low = 0x7fffffff, high = low + 1;

    v = w[0]&0xFF;
    v = v<<8 | w[1]&0xFF;
    v = v<<8 | w[2]&0xFF;
    v = v<<8 | w[3]&0xFF;

    return (long)(v & low) - (long)(v/2 & high/2) - (long)(v/2 & high/2);
    }

    Hint: in the three octet version, there should be one less
    assignment statement, and the initializer for 'low' needs
    a different value.
    Tim Rentsch, Mar 19, 2011
    #1
    1. Advertising

Want to reply to this thread or ask your own question?

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. redstripe

    twos complement data

    redstripe, Apr 21, 2006, in forum: VHDL
    Replies:
    3
    Views:
    2,462
  2. Replies:
    5
    Views:
    333
    Stephen Sprunk
    Aug 31, 2006
  3. James Kuyper
    Replies:
    3
    Views:
    335
    James Kuyper
    Mar 19, 2011
  4. Jorgen Grahn
    Replies:
    2
    Views:
    364
  5. Spiros Bousbouras
    Replies:
    6
    Views:
    410
    Ben Bacarisse
    Mar 18, 2011
Loading...

Share This Page