Sign in to follow this  
silverphyre673

I need someone to check if my program works on big-endian (Mac)

Recommended Posts

Hey all, I've been working on a hiscore system. It saves the hiscores to a binary file using a format and process I made myself. It tries to take into account both big and little endian systems. It works fine on my PC, which is little endian. I was hoping to get someone with a big-endian system (like a Mac) to test it out and make sure it works. If possible, please download it and test it out. You should just be able to put all the files together in a project using your favorite IDE or into a makefile for make, and compile them. They don't have any windows-only code. Thanks a lot, I appreciate it!

Share this post


Link to post
Share on other sites
I have a windows machine, but I still have a couple suggestions. I don't think that code would work quite the way you think it would.


// always specify the sign of a char in these cases...some systems have
// different defaults
char * ReverseByteOrder( const char * bytes )
{
// whats this for?
char swap;
// what if bytes isn't null terminated? Or what if its terminated too early?
unsigned int length = std::strlen(bytes);

// this points at one byte?
char * ret = new char[1];
// going out of bounds here
std::strcpy(ret, bytes);

for ( unsigned int i = 0, j = length-1; i < length; ++i, --j )
{

ret[i] = bytes[j];
}
return ret;
}



Here's some changes I think would help you, this still isn't the optimal solution, but its the first thing that popped into my head

#include <iostream>
#include <bitset>
#include <exception>
#include <climits>
using std::bitset;
using std::cout;
using std::endl;
using std::cerr;

void * ReverseByteOrder(const void *pValue, const std::size_t numBytes)
{
if( 0 == pValue ) throw(std::exception(__FUNCTION__));

std::size_t i, j = numBytes-1;
const unsigned char *pData = reinterpret_cast<const unsigned char*>(pValue);
unsigned char *pRetVal = new unsigned char[numBytes];

for(i=0; i < numBytes; ++i, --j )
pRetVal[i] = pData[j];

return(pRetVal);
}


int main()
{
unsigned int before = 1, *pAfter = NULL;
std::bitset<sizeof(int) * CHAR_BIT> b;

try{
b = before;
cout << "Before swap\t" << b << endl;


pAfter = (unsigned int*)ReverseByteOrder( &before, sizeof(before));

b = *pAfter;

cout << "After swap\t" << b << endl;


}
catch(std::exception &e)
{
cerr << e.what() << endl;
}
catch(...)
{
cerr << "An unknown exception has occurred" << endl;
}

delete [] pAfter;

return(0);
}








[EDIT]
Odd, well if it works it works I guess.. =) I could have sworn you should have been going out of bounds in a couple of spots there...
[/EDIT]

[Edited by - moeron on June 10, 2005 10:13:26 AM]

Share this post


Link to post
Share on other sites
Guest Anonymous Poster
Hello,

I didn't look at your code, sorry. Here is the output on a 32-bit big endian machine (G4 PPC):

Mary has 1904 points.
Ben has 18 points.
John has 18 points.
Bip has 9 points.
Jeremy has 8 points.
Bob has 8 points.


Hope this helps.

Share this post


Link to post
Share on other sites
I couldn't get hiscoresystem.cpp to compile, got the following warnings and errors from g++:

hiscoresystem.cpp: In member function `bool HiscoreSystem::Load()':
hiscoresystem.cpp:153: warning: comparison between signed and unsigned integer
expressions
hiscoresystem.cpp:173: error: type specifier omitted for parameter `score'
hiscoresystem.cpp:174: error: no matching function for call to `
std::vector<Hiscore, std::allocator<Hiscore> >::push_back(Hiscore
(&)(std::basic_string<char, std::char_traits<char>, std::allocator<char> >))
'
/usr/include/c++/3.3.2/bits/stl_vector.h:596: error: candidates are: void
std::vector<_Tp, _Alloc>::push_back(const _Tp&) [with _Tp = Hiscore, _Alloc
= std::allocator<Hiscore>]


Maybe i'm forgetting something, i'll come back and look at it when I get the chance.

Share this post


Link to post
Share on other sites
I've made some code changes - found one of the errors you mentioned. If you could re-download it, that would be great, because the line numbers have changed :) The original link should work fin.

I really appreciate you taking the time to do this, though. Thanks again!

Share this post


Link to post
Share on other sites
Your code relies on having a null terminated byte string (unsigned int length = std::strlen(bytes);)



Try this, it's more type safe than your solution - you should declare this in an anonymous namesapce and have wrappers for it only for types that it makes sense to endian-swap:


template<class T>
T& ReverseByteOrder(T& value)
{
unsigned char* ptr = reinterpret_cast<unsigned char*>(&value);

size_t index = 0;
for(;index<(sizeof(T)/2);++index)
{
std::swap(ptr[index],ptr[size - index -1]);
}

return value;
}

template<class T>
T ReverseByteOrder_copy(const T& value)
{
T value_copy = value;
ReverseByteOrder(value_copy);
return value_copy;
}


I don't have access to the actual code I use right now, so I had to write this from memory, but hopefully you get the idea.





Share this post


Link to post
Share on other sites
Quote:
Original post by Anonymous Poster
the endian won't and doesn't matter


Why not? I posted something on this a while ago and everyone told me it would. Anyways, I tried this:

entries_to_write = ReverseByteOrder_copy<int>(entries_to_write);

and similar on all the lines where I needed to reverse the byte order (changing <int> to <char*> when neccessary), but it gave me a bunch of linker errors, like this for example:

[Linker error] undefined reference to `int ReverseByteOrder<int>(int const&)'

I can't think of how I'm supposed to change the statement so it will work. Can you give me an example? Thanks.

Share this post


Link to post
Share on other sites
Ok I got it built on a G3 running at 233mhz (yeah, it's an old computer) on OS 10.2.8


Output of first run through the program:
ERROR: Load Failed!
1: Jack has 32 points.

Output 2:
1: Jack has 32 points.
2: Jane has 18 points

3rd time running it:
1: Jack has 32 points.
2: Jane has 18 points.
3: Jerry has 3 points.

4th time:
1: Jack has 32 points.
2: Jane has 18 points.
3: Jerry has 3 points.
4: Jerry has 3 points.

5th time:
1: Bobby has 39 points.
2: Jack has 32 points.
3: Jane has 18 points.
4: Jerry has 3 points.
5: Jerry has 3 points.


Wish I could help fix it, but my knowledge of getting endian stuff to work is a bit lacking.

Have you ever considered using a text file? It would mean not having to worry about the endian issue here. If you wanted you could compress the high scores or make up an encryption algorithm (it's not like you're protecting credit card numbers here, so if was broken it wouldn't matter) to make it a little harder for user to cheat.

Share this post


Link to post
Share on other sites
Forgot to mention I got these warnings compiling it:
hiscoresystem.cpp: In member function `bool HiscoreSystem::Load()':
hiscoresystem.cpp:156: warning: comparison between signed and unsigned integer
expressions

endianfunctions.cpp: In function `char* ReverseByteOrder(const char*)':
endianfunctions.cpp:11: warning: unused variable `char swap'


Also just tested in on a x86 linux box and got pretty much the same result


Also, to make it easier for someone else to test it OS X or linux here's a Makefile:

all: hiscore

hiscore: main.o hiscore.o hiscoresystem.o endianfunctions.o
g++ -Wall -o hiscore main.o hiscore.o hiscoresystem.o endianfunctions.o

main.o: main.cpp
g++ -Wall -c main.cpp

hiscore.o: hiscore.cpp hiscore.h
g++ -Wall -c hiscore.cpp

hiscoresystem.o: hiscoresystem.cpp hiscoresystem.h
g++ -Wall -c hiscoresystem.cpp

endianfunctions.o:
g++ -Wall -c endianfunctions.cpp

clean:
rm *.o hiscore



just remember to name the file Makefile
put it in the same directory as the code
go to the directory in the terminal
type make

Share this post


Link to post
Share on other sites
Quote:
Original post by silverphyre673
Well... I guess nobody is going to be transferring their hiscore file from a max to their PC :)

I think I'll just take it out. Thanks for your help, everyone!


I got the same problems on an x86 box running linux (so it's probably not an endian thing). I haven't had the time to look through your source yet.

I compiled your code with g++, is there a chance that in your code you're doing something that in standard c++ is undefined, which works with the microsoft compilers, but since it is undefined behaves differently in the GNU compilers?

I'll take a look around when I get the chance. Also, you might want to ask the same question in the forums at www.idevgames.com. There are many more mac game developers there than here.

Share this post


Link to post
Share on other sites
I'm using dev-cpp with mingw. I just took out the endian stuff, but haven't reloaded it. At some point tonight (when I'm done studying for finals tomorrow) I will try it on my linux box w/ g++. Thanks for all your help!

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

Sign in to follow this