Thread: long integers and byte order

  1. #1
    Registered User sonnichs's Avatar
    Join Date
    Jul 2011
    Posts
    30

    long integers and byte order

    I was preparing to send some bits down a serial port and I did a very simple thing. The bits were defined in a long int like this: long int lngint=19114957L;
    The hex representation of this string is, of course: 0123ABCD.

    I then did some gyrations to cast this string into a char array so that I could send it down the port:

    long int *liptr;
    char *cptr;
    char port_buffer[80];
    liptr=&lngint;

    cptr=(char*)liptr;
    strncpy(port_buffer,cptr,4);

    Things did not go as planned and after dumping the program, I found that the value stored in lngint, as as follows:

    CD AB 23 01

    The resulting character string of course, flew down the port backwards!

    Clearly for this compiler/processor the highest addressed byte contains the most significant digits of the long int. Now-I can load the port_buffer array by hand, byte by byte, reversing the order. But this may not be a good idea. Perusing the few C books I have it appears that there is no standard as to how byte order for a long int is stored on a processor. I am using 186 platforms. Is the byte order conserved with other processors? I know that at least when dealing with discrete semiconductor components, bit ordering is not always consistent.

    Regards,
    Fritz

  2. #2
    Banned
    Join Date
    Aug 2010
    Location
    Ontario Canada
    Posts
    9,547
    Read this....Endianness - Wikipedia, the free encyclopedia

    And next time use sprintf() to prepare your string...

  3. #3
    spurious conceit MK27's Avatar
    Join Date
    Jul 2008
    Location
    segmentation fault
    Posts
    8,300
    Quote Originally Posted by sonnichs View Post
    Perusing the few C books I have it appears that there is no standard as to how byte order for a long int is stored on a processor. I am using 186 platforms.
    There are standards WRT byte order, two of them. Guess what they are ?

    The order for x86, as you've just discovered, is little endian.

    Is the byte order conserved with other processors?
    Historically a lot of network servers used a (non-x86) architecture with big endianian byte order, hence it is sometimes called "network byte order" and it still the norm in networking, so there are networking library functions to convert.
    C programming resources:
    GNU C Function and Macro Index -- glibc reference manual
    The C Book -- nice online learner guide
    Current ISO draft standard
    CCAN -- new CPAN like open source library repository
    3 (different) GNU debugger tutorials: #1 -- #2 -- #3
    cpwiki -- our wiki on sourceforge

  4. #4
    spurious conceit MK27's Avatar
    Join Date
    Jul 2008
    Location
    segmentation fault
    Posts
    8,300
    Quote Originally Posted by CommonTater View Post
    And next time use sprintf() to prepare your string...
    I don't think that will accomplish what the OP wants, which is a bytestream (not a string representation).

    Might be clearer to use an unsigned char array but it really doesn't matter.
    C programming resources:
    GNU C Function and Macro Index -- glibc reference manual
    The C Book -- nice online learner guide
    Current ISO draft standard
    CCAN -- new CPAN like open source library repository
    3 (different) GNU debugger tutorials: #1 -- #2 -- #3
    cpwiki -- our wiki on sourceforge

  5. #5
    Banned
    Join Date
    Aug 2010
    Location
    Ontario Canada
    Posts
    9,547
    Quote Originally Posted by MK27 View Post
    I don't think that will accomplish what the OP wants, which is a bytestream (not a string representation).

    Might be clearer to use an unsigned char array but it really doesn't matter.
    Very often the easiest way to convert is to use sprintf() when sending and sscanf() when receiving... it eliminates the whole endian thing quite nicely.

    Of course if you must transfer raw binary there's ntohl() and htonl() in the sockets library. Send in network order, convert to host order after receiving.

  6. #6
    Registered User
    Join Date
    Jun 2005
    Posts
    6,815
    Quote Originally Posted by MK27 View Post
    There are standards WRT byte order, two of them. Guess what they are ?

    The order for x86, as you've just discovered, is little endian.
    You got the number wrong: there are more than two real-world byte orders. Look up "middle endian".

    There are also some hardware architectures that are bi-endian, meaning they can be configured to different endianness in data segments and/or code segments.
    Right 98% of the time, and don't care about the other 3%.

    If I seem grumpy or unhelpful in reply to you, or tell you you need to demonstrate more effort before you can expect help, it is likely you deserve it. Suck it up, Buttercup, and read this, this, and this before posting again.

  7. #7
    Banned
    Join Date
    Aug 2010
    Location
    Ontario Canada
    Posts
    9,547
    Quote Originally Posted by grumpy View Post
    You got the number wrong: there are more than two real-world byte orders. Look up "middle endian".

    There are also some hardware architectures that are bi-endian, meaning they can be configured to different endianness in data segments and/or code segments.
    And what are the odds of running into any of that on a modern system?

    (Serious question.... not being facetious...)
    Last edited by CommonTater; 08-11-2011 at 07:39 AM.

  8. #8
    spurious conceit MK27's Avatar
    Join Date
    Jul 2008
    Location
    segmentation fault
    Posts
    8,300
    Quote Originally Posted by CommonTater View Post
    Very often the easiest way to convert is to use sprintf() when sending and sscanf() when receiving... it eliminates the whole endian thing quite nicely.
    Most likely endianness actually isn't really an issue -- there are no conversions necessary, just the OP was unaware that the bytes in an int are the reverse of what you might assume.

    Using offsets into a bytes stream and casting to type, or just reading the whole thing into a struct, is easier and faster than using string functions (and definitely more conventional). If you do need a conversion, as you mention there are simple functions for that.

    Quote Originally Posted by grumpy View Post
    You got the number wrong: there are more than two real-world byte orders.
    I stand corrected! What we really need for a proper challenge is indeterminate byte ordering.
    Last edited by MK27; 08-11-2011 at 07:38 AM.
    C programming resources:
    GNU C Function and Macro Index -- glibc reference manual
    The C Book -- nice online learner guide
    Current ISO draft standard
    CCAN -- new CPAN like open source library repository
    3 (different) GNU debugger tutorials: #1 -- #2 -- #3
    cpwiki -- our wiki on sourceforge

  9. #9
    Registered User
    Join Date
    Jun 2005
    Posts
    6,815
    Quote Originally Posted by CommonTater View Post
    And what are the odds of running into any of that on a modern system?

    (Serious question.... not being facetious...)
    Some ISO 8583 communications protocols (used for authorisation of financial transactions) are middle-endian. Processors in embedded systems that natively use such protocols (such as POS systems) will either be middle-endian or emulate middle-endian behaviour. There are a few of those around in the modern world.
    Right 98% of the time, and don't care about the other 3%.

    If I seem grumpy or unhelpful in reply to you, or tell you you need to demonstrate more effort before you can expect help, it is likely you deserve it. Suck it up, Buttercup, and read this, this, and this before posting again.

  10. #10
    Registered User sonnichs's Avatar
    Join Date
    Jul 2011
    Posts
    30
    Thanks for the replies. I gained my expertise (now long gone!) on Univacs, 370s and Solaris. I am pretty sure these were big-endian. I will play it safe and not rely on an given byte order as my code will probably get ported to 6800 processors and perhaps some ARM devices.

    I did not find any functions that simply take a long int and convert it directly into a char string in proper order. There are a few conversions on the FAQ for this forum but not for this purpose.

    Cheers
    Fritz

  11. #11
    Banned
    Join Date
    Aug 2010
    Location
    Ontario Canada
    Posts
    9,547
    Quote Originally Posted by sonnichs View Post
    I did not find any functions that simply take a long int and convert it directly into a char string in proper order. There are a few conversions on the FAQ for this forum but not for this purpose.
    That's why I mentioned sprintf() and sscanf() ... The idea is pretty simple, a string is a series of bytes, they have no endian issues so if you take your value --lets say 123--- and covert that to a string with sprintf() and send it, it goes out in byte order left to right... the other end gets "123", now you convert that from a string to an int with sscanf() on the target machine... sscanf() will write the value to an int *in the correct endian orientation for that machine* ... now you don't have to worry about big endian, little endian, whatever... in fact you don't even need to know... because the int to string to int conversion takes care of it for you.
    Last edited by CommonTater; 08-11-2011 at 09:04 PM.

  12. #12
    Registered User
    Join Date
    Jun 2005
    Posts
    6,815
    Quote Originally Posted by sonnichs View Post
    I did not find any functions that simply take a long int and convert it directly into a char string in proper order.
    Depends what you mean by "proper order".

    One option is using sprintf() and scanf().

    Another option - assuming you are only attempting to move 16 and 32 bit unsigned integers between systems, and are happy to transmit them in a binary format - is use of functions that convert to and from network byte order. Look up functions named htons(), htonl(), ntohs(), and ntohl(). Virtually all systems that support IP networking support these functions in some way (although these functions are not standard C, so you will have to read documentation for your compiler and/or host system).
    Right 98% of the time, and don't care about the other 3%.

    If I seem grumpy or unhelpful in reply to you, or tell you you need to demonstrate more effort before you can expect help, it is likely you deserve it. Suck it up, Buttercup, and read this, this, and this before posting again.

  13. #13
    Registered User sonnichs's Avatar
    Join Date
    Jul 2011
    Posts
    30
    One thing that I didnt' mention is that the receiving machine is a spectrometer-I don't have access to its code etc. The compiler/microprocessor that I am using does not support htonxx() routines.

    I am not sure that sscanf and ssprintf are useful here. I am not dealing with ASCII. For example I need to send the spectrometer a 4 byte buffer that contains a time delay. My code after many gyrations calculates this delay as a long int. Thus my process to sendthe device a time delay of: 6844 would be:

    int long tdelay=6844;
    char outbuff[4];
    convert_routine(tdelay,outbuff);

    Now outbuff must contain: 00 01 0A BC

    If i used sprintf I think I would have ended up with 31 41 42 43 which is the ASCII representation of the hex string that I was trying to generate.

  14. #14
    Banned
    Join Date
    Aug 2010
    Location
    Ontario Canada
    Posts
    9,547
    Quote Originally Posted by sonnichs View Post
    One thing that I didnt' mention is that the receiving machine is a spectrometer-I don't have access to its code etc. The compiler/microprocessor that I am using does not support htonxx() routines.

    I am not sure that sscanf and ssprintf are useful here. I am not dealing with ASCII. For example I need to send the spectrometer a 4 byte buffer that contains a time delay. My code after many gyrations calculates this delay as a long int. Thus my process to sendthe device a time delay of: 6844 would be:

    int long tdelay=6844;
    char outbuff[4];
    convert_routine(tdelay,outbuff);

    Now outbuff must contain: 00 01 0A BC
    Ok now I get it... So you're looking to send binary values... In that case I'd run my DWORD through a union...
    Code:
    union t_CONV
      { unsigned long int W;
         unsigned char    B[sizeof(input)]; }
    CONV;
    This will work in both directions... you can assign an integer value to W and read individual bytes out of B in any order you want. You can also assign bytes to B and read the DWORD value from W.... A little experimentation should help you decide if you want to read/write B as 0, 1, 2, 3 or 3, 2, 1, 0... so you now have full control over the endianness of the communications...

  15. #15
    Registered User
    Join Date
    Jun 2005
    Posts
    6,815
    Quote Originally Posted by sonnichs View Post
    int long tdelay=6844;
    char outbuff[4];
    convert_routine(tdelay,outbuff);

    Now outbuff must contain: 00 01 0A BC
    Are you sure? 6844 when converted to hex is 00 00 1A BC.

    Anyway, assuming the values I infer are correct....
    Code:
    //  note:  untested code follows;  it shows the idea.   Use at own risk
    
    void my_possibly_wrong_convert_routine(unsigned long tdelay, unsigned char outbuf[])
    {
        int i;
        for (i = 0; i < 3; ++i)
        {
             outbuf[3-i] = tdelay % 0x100;
             tdelay /= 0x100;
        }
    }
    The magic value here (0x100) is 0xFF + 1 (i.e. 256). All I'm doing is doing repeated remainders and division by 256.

    If the values you supplied are correct, then you will need to swap a couple of nibbles (a nibble is half a byte) relative to this. Assuming you only want to swap the 1 in the second byte (outbuf[1]) and the zero in the third byte (outbuf[2]) then ...
    Code:
    //  note:  untested code follows; it shows the idea.   Use at own risk
    
    void your_possibly_wrong_convert_routine(unsigned long tdelay, unsigned char outbuf[])
    {
        unsigned char temp[2];
        my_possibly_wrong_convert_routine(tdelay, outbuf);
        temp[0] = (outbuf[1] % 0x10)*0x10 + outbuf[2]  / 0x10; 
        temp[1] = (outbuf[2] % 0x10)*0x10 + outbuf[1] / 0x10;
        outbuf[2] = temp[1];
        outbuf[1] = temp[0];
    }
    The magic value here, 0x10 is 0xF + 1 (i.e. 16). Assuming an unsigned char has a range 0-255, dividing by 16 extracts the upper nibble, and modulo 16 extracts the lower nibble of a char. Then you just need to rebuild two characters with the nibbles swapped as needed.

    This is not the only way to produce the bytes you suggest from a value 6844. If I've got the order wrong (check what other values should produce) then you will need to adjust.

    Note that I've deliberately used unsigned types here, and assumed sizeof(unsigned long) is 4.
    Last edited by grumpy; 08-12-2011 at 08:32 AM.
    Right 98% of the time, and don't care about the other 3%.

    If I seem grumpy or unhelpful in reply to you, or tell you you need to demonstrate more effort before you can expect help, it is likely you deserve it. Suck it up, Buttercup, and read this, this, and this before posting again.

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. Conver long to 8 byte array and back to long
    By plopes in forum C Programming
    Replies: 3
    Last Post: 04-01-2009, 12:39 AM
  2. byte order change
    By onebrother in forum C Programming
    Replies: 1
    Last Post: 08-06-2007, 05:40 AM
  3. changing byte order of an unsigned long?
    By stustu92 in forum C Programming
    Replies: 6
    Last Post: 01-27-2006, 06:21 AM
  4. byte and bit order question
    By chunlee in forum C Programming
    Replies: 7
    Last Post: 11-07-2004, 01:50 PM
  5. byte to long
    By Unregistered in forum C++ Programming
    Replies: 8
    Last Post: 10-22-2001, 12:27 PM