# Homework Help: Endian Conversion

1. Mar 24, 2012

### sunmaz94

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?

2. Mar 25, 2012

### I like Serena

Hi sunmaz94!

Your code seems fine to me.

For which numbers would it go wrong?
Perhaps you print the result as a signed integer?

3. Mar 25, 2012

### rcgldr

So num is declared as an unsigned int?

4. Mar 25, 2012

### sunmaz94

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".

5. Mar 25, 2012

### I like Serena

Okay.
I still believe the code you showed is right.
Perhaps you can show the rest of your code?

6. Mar 25, 2012

### sunmaz94

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;
}

7. Mar 25, 2012

### sunmaz94

As a separate point, my binary conversions are actually way off. Any ideas there?

8. Mar 25, 2012

### I like Serena

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.

9. Mar 25, 2012

### I like Serena

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.

10. Mar 25, 2012

### sunmaz94

I'm far too used to Java. How do I resolve this? Do I reset or free the static variable somehow?

11. Mar 25, 2012

### I like Serena

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.

12. Mar 25, 2012

### sunmaz94

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.

13. Mar 25, 2012

### sunmaz94

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?

14. Mar 25, 2012

### I like Serena

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".

15. Mar 25, 2012

### sunmaz94

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?

16. Mar 25, 2012

### sunmaz94

Thank you very much for the clear explanation. That makes sense. I wasn't aware that static behaved that way in C.

17. Mar 25, 2012

### I like Serena

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.

18. Mar 25, 2012

### I like Serena

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.

19. Mar 25, 2012

### sunmaz94

Never mind. That was dumb. I fixed it:

Code (Text):
static char littleEndianBinary[32 + + 7 + 1];
littleEndianBinary[0] = '\0';
Thanks again!

20. Mar 25, 2012

### sunmaz94

Okay i'll change this. Thanks!

21. Mar 25, 2012

### sunmaz94

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?

22. Mar 25, 2012

### I like Serena

Can you copy+paste your test run?

23. Mar 25, 2012

### sunmaz94

I edited the previous post to include said information.

24. Mar 25, 2012

### I like Serena

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?

25. Mar 25, 2012

### sunmaz94

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;
}