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!

Homework Help: 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!
     
  22. Mar 25, 2012 #21
    Now the binary issue is fixed.

    However, I still appear to overflow.

    When entering 355,220,054 I get 1,446,652,928 instead of the, correct, 1,446,652,949.

    Code (Text):
    Enter a natural number to convert from little to big endian: (0 to quit)
    355220054
    Converting 355220054 to big endian...
    The number in little endian binary is: 0001 0101 0010 1100 0011 1010 0101 0110
    The number in big endian binary is:    0101 0110 0011 1010 0010 1100 0000 0000
    The number in big endian is:           1446652928

    Any ideas as to the cause of this issue or as to how it can be remedied?
     
  23. Mar 25, 2012 #22

    I like Serena

    User Avatar
    Homework Helper

    Can you copy+paste your test run?
     
  24. Mar 25, 2012 #23
    I edited the previous post to include said information.
     
  25. Mar 25, 2012 #24

    I like Serena

    User Avatar
    Homework Helper

    It still looks like an access violation.
    If you take a look at the big endian binary output, you'll see that the least significant byte is zero.
    Obviously it has been overwritten.

    What does your code look like now?
    Did you introduce a char array in your program?
    If so, is it large enough?
     
  26. Mar 25, 2012 #25
    I am now passing by reference. It looks to me more like overflow than an access violation...

    The 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.
     */
    void decimalToBinary(unsigned long decimal, char* result) {
        int i;
        for (i = 31; i >= 0; i--) {
            if (((decimal&(1<<i))>>i) == 1) {
                strcat(result, "1");
            } else {
                strcat(result, "0");
            }

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

    /*
     * Allows a user to convert a 32-bit integer from little to big endian.
     * Displays the numbers in binary as well.
     */
    int main() {
        unsigned long littleEndian;
        char littleEndianBinary[32 + 7 + 1];
        unsigned long bigEndian;
        char bigEndianBinary[32 + 7 + 1];
       
        /* 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[0] = '\0';
            decimalToBinary(littleEndian, &littleEndianBinary);

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

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

            printf("The number in big endian is:           %'lu\n", bigEndian);
        };
       
        return EXIT_SUCCESS;
    }
     
Share this great discussion with others via Reddit, Google+, Twitter, or Facebook