Endian Conversion C Program: Convert 32-Bit Integer Little to Big

  • Thread starter sunmaz94
  • Start date
In summary: It's not poor practice, it's just that you are using it wrong.In general I would not use a static variable in functions for return values, just for data that needs to be kept from one function call to the next.In your case it's better to allocate the buffer in the function and return a pointer to it.That way you can handle a different buffer for each call and it's also thread safe.In summary, the code provided by the original poster for converting a 32-bit integer from little to big endian appears to be correct. However, there may be an issue with the rest of the code causing unexpected results. Additionally, the use of a static variable for string concatenation can lead to memory leaks and unpredictable
  • #1
sunmaz94
42
0

Homework Statement



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

Homework Equations


None.

The Attempt at a Solution



Code:
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.
 
Physics news on Phys.org
  • #2
Hi sunmaz94! :smile:

sunmaz94 said:

Homework Statement



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


Homework Equations


None.


The Attempt at a Solution



Code:
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.

Your code seems fine to me.

For which numbers would it go wrong?
Perhaps you print the result as a signed integer?
 
  • #3
So num is declared as an unsigned int?
 
  • #4
I like Serena said:
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?

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
Okay.
I still believe the code you showed is right.
Perhaps you can show the rest of your code?
 
  • #6
I like Serena said:
Okay.
I still believe the code you showed is right.
Perhaps you can show the rest of your code?

Certainly. Thanks for looking into this.

Below is the full code:

Code:
#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
As a separate point, my binary conversions are actually way off. Any ideas there?
 
  • #8
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
sunmaz94 said:
As a separate point, my binary conversions are actually way off. Any ideas there?

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
I like Serena said:
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.

I'm far too used to Java. How do I resolve this? Do I reset or free the static variable somehow?
 
  • #11
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
I like Serena said:
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.

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
I like Serena said:
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.

Actually, that doesn't resolve the issue. Perhaps I have misunderstood your suggestion?

I modified it so that:

Code:
static char littleEndianBinary[32 + + 7 + 1] = "\0";

Is this somehow insufficient?
 
  • #14
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
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
I like Serena said:
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".

Thank you very much for the clear explanation. That makes sense. I wasn't aware that static behaved that way in C.
 
  • #17
sunmaz94 said:
Actually, that doesn't resolve the issue. Perhaps I have misunderstood your suggestion?

I modified it so that:

Code:
static char littleEndianBinary[32 + + 7 + 1] = "\0";

Is this somehow insufficient?

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:
littleEndianBinary[0] = '\0';
outside the declaration.
 
  • #18
sunmaz94 said:
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?

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
sunmaz94 said:
Actually, that doesn't resolve the issue. Perhaps I have misunderstood your suggestion?

I modified it so that:

Code:
static char littleEndianBinary[32 + + 7 + 1] = "\0";

Is this somehow insufficient?

Never mind. That was dumb. I fixed it:

Code:
static char littleEndianBinary[32 + + 7 + 1];
littleEndianBinary[0] = '\0';

Thanks again!
 
  • #20
I like Serena said:
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.

Okay i'll change this. Thanks!
 
  • #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:
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
Can you copy+paste your test run?
 
  • #23
I like Serena said:
Can you copy+paste your test run?

I edited the previous post to include said information.
 
  • #24
sunmaz94 said:
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:
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?

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
I like Serena said:
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?

I am now passing by reference. It looks to me more like overflow than an access violation...

The code:


Code:
#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;
}
 
  • #26
sunmaz94 said:
I am now passing by reference. It looks to me more like overflow than an access violation...

It's an access violation.
Your character array is one short.
You write 32 digits, 8 spaces, and 1 zero character.

The result is that you overwrite the first byte of the variable that comes after, with a zero.
 
  • #27
Since you appear to be trying to do this properly, let me give you a couple more pointers.

When you use scanf(), you do not reinitialize the variable littleEndian to zero before the call.
As a result, your program will hang if you enter any character that is not a digit.

You return the return value of strcat(), but now you have a void function that is not supposed to return a value.
I recommend using extra compiler switches to warn you against mistakes like this.

The use of strcat(s, "\0") serves no purpose.
When you write literally "" in C, an ending zero is implied.
The string "\0" is effectively 2 zeroes.
strcat() itself already concatenates an ending zero, so concatenating an empty string does not do anything.
 
  • #28
I like Serena said:
It's an access violation.
Your character array is one short.
You write 32 digits, 8 spaces, and 1 zero character.

The result is that you overwrite the first byte of the variable that comes after, with a zero.

That makes perfect sense. Thanks!

I should only be writing 7 spaces... I am writing one at the end it seems. I'll add a condition to my space-writing if statement.
 
  • #29
I like Serena said:
Since you appear to be trying to do this properly, let me give you a couple more pointers.

When you use scanf(), you do not reinitialize the variable littleEndian to zero before the call.
As a result, your program will hang if you enter any character that is not a digit.

You return the return value of strcat(), but now you have a void function that is not supposed to return a value.
I recommend using extra compiler switches to warn you against mistakes like this.

The use of strcat(s, "\0") serves no purpose.
When you write literally "" in C, an ending zero is implied.
The string "\0" is effectively 2 zeroes.
strcat() itself already concatenates an ending zero, so concatenating an empty string does not do anything.

These are all excellent pointers. Thank you very much for the constructive criticism!
 
  • #30
Everything now functions correctly.

Thank you very much ILS for all of your assistance. It is much appreciated.
 

1. What is endian conversion in a C program?

Endian conversion in a C program refers to the process of changing the byte order of a data type from little-endian to big-endian or vice versa. This is important when transferring data between systems with different endianness, as it ensures that the data is interpreted correctly.

2. Why is endian conversion necessary?

Endian conversion is necessary because different computer architectures and processors have different ways of storing data in memory. Some store the most significant byte (MSB) first, while others store the least significant byte (LSB) first. Endian conversion ensures that data is consistent and can be properly interpreted by different systems.

3. How does the 32-bit integer conversion from little to big endian work?

The 32-bit integer conversion from little to big endian involves swapping the position of the bytes in the data type. In little-endian, the LSB is stored in the lowest memory address, while the MSB is stored in the highest memory address. In big-endian, the MSB is stored in the lowest memory address, while the LSB is stored in the highest memory address. Therefore, to convert from little to big endian, the bytes of the 32-bit integer are swapped.

4. Can endian conversion be done for other data types besides 32-bit integers?

Yes, endian conversion can be done for other data types such as 16-bit integers, 64-bit integers, and floating-point numbers. The process is similar to converting a 32-bit integer, where the bytes are swapped to match the desired endianness.

5. Are there any built-in functions in C for endian conversion?

No, there are no built-in functions in C for endian conversion. However, there are libraries and functions available that can assist with endian conversion, such as the "htons" and "ntohs" functions in the arpa/inet.h library.

Similar threads

  • Engineering and Comp Sci Homework Help
Replies
2
Views
1K
  • Engineering and Comp Sci Homework Help
Replies
3
Views
1K
  • Engineering and Comp Sci Homework Help
Replies
1
Views
2K
  • Engineering and Comp Sci Homework Help
Replies
1
Views
4K
  • Engineering and Comp Sci Homework Help
Replies
5
Views
1K
  • Programming and Computer Science
Replies
32
Views
1K
  • Engineering and Comp Sci Homework Help
Replies
7
Views
2K
  • Engineering and Comp Sci Homework Help
Replies
3
Views
4K
  • Engineering and Comp Sci Homework Help
Replies
7
Views
2K
  • Engineering and Comp Sci Homework Help
Replies
2
Views
2K
Back
Top