1. Limited time only! Sign up for a free 30min personal tutor trial with Chegg Tutors
    Dismiss Notice
Dismiss Notice
Join Physics Forums Today!
The friendliest, high quality science and math community on the planet! Everyone who loves science is here!

Endian Conversion

  1. Mar 24, 2012 #1
    1. The problem statement, all variables and given/known data

    Write a C program that converts a 32-bit integer from little to big endian.


    2. Relevant equations
    None.


    3. The attempt at a solution

    Code (Text):
    return (((num&0x000000FF)<<24) + ((num&0xFF000000)>>24)) + ((num&0x0000FF00)<<8) + ((num&0x00FF0000)>>8);
    This works for small numbers but fails when they get large. Everything is stores in unsigned long ints.

    Any idea as to what is wrong?

    Thanks in advance.
     
  2. jcsd
  3. Mar 25, 2012 #2

    I like Serena

    User Avatar
    Homework Helper

    Hi sunmaz94! :smile:

    Your code seems fine to me.

    For which numbers would it go wrong?
    Perhaps you print the result as a signed integer?
     
  4. Mar 25, 2012 #3

    rcgldr

    User Avatar
    Homework Helper

    So num is declared as an unsigned int?
     
  5. Mar 25, 2012 #4
    It works for 257, outputting 16,842,752.

    It fails on 355,220,054 outputting a number slightly smaller than the correct answer instead of the correct answer, 1,446,652,949.
    Interestingly, it sometimes works. I just ran it and it was correct for the larger number as well.

    num is an unsigned long int. All variables are. Everything is printed and scanned in as: "%lu".
     
  6. Mar 25, 2012 #5

    I like Serena

    User Avatar
    Homework Helper

    Okay.
    I still believe the code you showed is right.
    Perhaps you can show the rest of your code?
     
  7. Mar 25, 2012 #6
    Certainly. Thanks for looking into this.

    Below is the full code:

    Code (Text):

    #include <stdlib.h>
    #include <stdio.h>
    #include <string.h>
    #include <locale.h>

    #define TRUE    1

    /* Converts from little to big endian or vice-versa
     * Labeling bytes from 0 to 3, left to right, this effectively performs the following swaps:
     * 0 <-> 3
     * 1 <-> 2
     * Thus given a little or big endian unsigned long it will go from 0,1,2,3 to 3,2,0,1 relative to the previously mentioned byte order.
     * This swaps the bytes correctly to inter-convert between the two formats.
     * The below bit-wise operations perform these swaps.
     */
    unsigned long switchEndianess(unsigned long num) {
        return (((num&0x000000FF)<<24) + ((num&0xFF000000)>>24)) + ((num&0x0000FF00)<<8) + ((num&0x00FF0000)>>8);
    }

    /* Converts a 32 bit long integer into binary.
     *
     */
    char* decimalToBinary(unsigned long decimal) {
        static char littleEndianBinary[32 + + 7 + 1];
       
        int i;
        for (i = 31; i >= 0; i--) {
            if (((decimal&(1<<i))>>i) == 1) {
                strcat(littleEndianBinary, "1");
            } else {
                strcat(littleEndianBinary, "0");
            }

            if ((i % 4) == 0) {
                strcat(littleEndianBinary, " ");
            }
        }
        return strcat(littleEndianBinary, "\0");
    }

    int main() {
        unsigned long littleEndian;
        char* littleEndianBinary;
        unsigned long bigEndian;
        char* bigEndianBinary ;
       
        /* set the numereic locale to the system default locale */
        /* Note that this would cause numbers to be printed with thousands seperators on a newer system,
         * through the use of the "'" flag for printf.
        */
        setlocale (LC_NUMERIC, "");
       
        while(TRUE) {
            printf("Enter a natural number to convert from little to big endian: (0 to quit)\n");
            /* get input */
            scanf("%lu", &littleEndian);
           
            /* break on sentinal */
            if (littleEndian == 0) {
                break;
            }
           
            printf("Converting %'lu to big endian...\n", littleEndian);

            littleEndianBinary = decimalToBinary(littleEndian);

            printf("The number in little endian binary is: %s\n", littleEndianBinary); 
           
            bigEndian = switchEndianess(littleEndian);
           
            bigEndianBinary = decimalToBinary(bigEndian);

            printf("The number in big endian binary is: %s\n", bigEndianBinary);

            printf("The number in big endian is: %'lu\n", bigEndian);
        };
       
        return EXIT_SUCCESS;
    }
     
  8. Mar 25, 2012 #7
    As a separate point, my binary conversions are actually way off. Any ideas there?
     
  9. Mar 25, 2012 #8

    I like Serena

    User Avatar
    Homework Helper

    Did you notice that the binary representation is not printed correctly the second time (and the times after)?

    This is the reason your program behaves in unexpected ways.
     
  10. Mar 25, 2012 #9

    I like Serena

    User Avatar
    Homework Helper

    Ah, you did notice.

    Did you know that a static variable retains its value?
    If you concatenate to it without resetting, it will grow out of its memory and cause madness and chaos.
     
  11. Mar 25, 2012 #10
    I'm far too used to Java. How do I resolve this? Do I reset or free the static variable somehow?
     
  12. Mar 25, 2012 #11

    I like Serena

    User Avatar
    Homework Helper

    In C strings end on a '\0' character.
    Set the first character of your static string to zero when you enter your function and it should work.
     
  13. Mar 25, 2012 #12
    I was aware of the first point. Could you elaborate as to why the second point is causative of a resolution to the memory leak and non-deterministic behavior?

    Thanks again for all your assistance.
     
  14. Mar 25, 2012 #13
    Actually, that doesn't resolve the issue. Perhaps I have misunderstood your suggestion?

    I modified it so that:

    Code (Text):
    static char littleEndianBinary[32 + + 7 + 1] = "\0";
    Is this somehow insufficient?
     
  15. Mar 25, 2012 #14

    I like Serena

    User Avatar
    Homework Helper

    In your function you declare a "static" string meaning it retains its value between function calls.
    The first time you write a binary string into it.
    The second time, its value is still present, so you concatenate your 2nd binary string to it.

    The strcat() function searches for a '\0' character in the string and concatenates at that point.

    Since you only allocated 32+7+1 characters for it, the second time you are overwriting memory that does not belong to this string.
    The language C does not warn against that, but simply writes to memory it's not supposed to write to.

    Since your variable and other important stuff is also somewhere in memory, they get damaged leading to unpredictable results, like seeing different values than you entered.

    In general whenever a program behaves in unexpected ways, there is always such an "access violation".
     
  16. Mar 25, 2012 #15
    Also is my use of a static variable in this instance poor programming practice? Should I be passing in the char array by reference instead? Is passing the value to convert by value okay pedagogically speaking?
     
  17. Mar 25, 2012 #16
    Thank you very much for the clear explanation. That makes sense. I wasn't aware that static behaved that way in C.
     
  18. Mar 25, 2012 #17

    I like Serena

    User Avatar
    Homework Helper

    Yes, that is insufficient.
    It's a one-time initialization that does not carry over to a 2nd call.
    You need to explicitly set:
    Code (Text):
    littleEndianBinary[0] = '\0';
    outside the declaration.
     
  19. Mar 25, 2012 #18

    I like Serena

    User Avatar
    Homework Helper

    Yes, use of a static variable in a function is poor programming practice.
    Passing the char array by reference is much better.
    Passing the value to convert by value is okay, since it's only a simple value.
     
  20. Mar 25, 2012 #19
    Never mind. That was dumb. I fixed it:

    Code (Text):
    static char littleEndianBinary[32 + + 7 + 1];
    littleEndianBinary[0] = '\0';
    Thanks again!
     
  21. Mar 25, 2012 #20
    Okay i'll change this. Thanks!
     
Know someone interested in this topic? Share this thread via Reddit, Google+, Twitter, or Facebook




Similar Discussions: Endian Conversion
  1. Data Conversion (Replies: 1)

  2. Units Conversion (Replies: 3)

Loading...