gbadev.org forum archive

This is a read-only mirror of the content originally found on forum.gbadev.org (now offline), salvaged from Wayback machine copies. A new forum can be found here.

C/C++ > atoi() / string to integer / reading from a battery save

#75890 - phoenixj91 - Thu Mar 16, 2006 9:58 pm

I'm writing a simple battery save function for my game. All I need to do is save an integer (hiscore) to SRAM on gameover and read that same integer back when the game initially starts.
I have no trouble writing the score to SRAM, the sav file VBA looks fine when I open it in a hex editor. Loading is another issue, however. I'm pretty sure that I'm getting my data from SRAM, but it's not converting into an integer properly. I end up with the same number no matter what the integer is - 10944.

Code:

int LoadInt(u16 offset)
{
   int  i, temp=0;
   char string[7];

   for(i = 0; i != 7; i++)
   {
      string[i] = *(u8 *)(SRAM + offset + i);
                                temp=(temp*10)+((int)string[i]-48);
   }

   return temp;
}

This function originally used the atoi() function to convert string[] to an integer. I can't afford to include that library in my project, though. So instead I do it on the fly - multiply a temporary number by 10, and adding the individual digits in. The 48 is to compensate for ASCII codes, since 0's ASCII code is 48.


Code:

void SaveInt(u16 offset, int value)
{
   //Looping variable
   int i;
   
   //Temp string
   char string[7];

   posprintf(string, "%d", value);

   for(i=0; i < 32768; i++)
   {
      if(string[i] == NULL)
      {
         break;
      }

      *(u8 *)(SRAM + offset + i) = string[i];
   }
}

My save function, just for completeness.

#75909 - sajiimori - Thu Mar 16, 2006 11:12 pm

I haven't read your code, but why don't you just write the number directly instead of encoding it as a string and decoding it later?

#75914 - phoenixj91 - Thu Mar 16, 2006 11:31 pm

Solved the problem, the loop didn't terminate on a null character but kept going till it hit 7.

#75916 - poslundc - Thu Mar 16, 2006 11:36 pm

The point is still salient, though: why convert to and from a different, less efficient format unnecessarily?

Dan.

#75928 - phoenixj91 - Fri Mar 17, 2006 1:24 am

I assumed that was the way SRAM worked, the functions were copied directly from the Saving demo in the Sources section of gbadev

#75932 - sajiimori - Fri Mar 17, 2006 2:18 am

You're missing the point. ASCII characters are 8 bit numbers. SRAM doesn't know if the number 65 "means" the letter 'A' or that the player got to level 65.

It's pointless to write the number for the ASCII character '6' followed by the number for the ASCII character '5' when you could have just written the number 65.

#75933 - phoenixj91 - Fri Mar 17, 2006 2:26 am

I understand that. I wasn't defending the functions I posted, I was saying that before this thread I had assumed you needed to write to SRAM in chars. I was wrong, though I learned from my mistake ^_-

#75935 - sajiimori - Fri Mar 17, 2006 3:41 am

You do have to write it in chars -- 8 bit numbers. That doesn't mean you have to encode it in ASCII! :)

#75942 - phoenixj91 - Fri Mar 17, 2006 4:55 am

So instead of declaring string[] as
Code:
char string[7]

I'd go
Code:
u8 string[7]

?[/code]

#75944 - tepples - Fri Mar 17, 2006 5:13 am

They're the same thing. The type 'char' is equivalent to 'unsigned char' within devkitARM, and 'u8' is typically typedef'd as 'unsigned char'.

What you want is a more efficient and more reliable format for storing the data. Instead of serializing the data in ASCII form, try serializing it in plain old big-endian binary form[1]:

Code:
/* Caution: untested */

void SRAM_putInt(size_t offset, u32 data)
{
  SRAM[offset + 0] = (score >> 24) & 0x00FF;
  SRAM[offset + 1] = (score >> 16) & 0x00FF;
  SRAM[offset + 2] = (score >> 8) & 0x00FF;
  SRAM[offset + 3] = (score >> 0) & 0x00FF;
}

u32 SRAM_getInt(size_t offset)
{
  u32 result
      = (SRAM[offset + 0] << 24)
      | (SRAM[offset + 1] << 16)
      | (SRAM[offset + 2] << 8)
      | (SRAM[offset + 3] << 0)
};


[1] The GBA natively uses little-endian, but serializing in big-endian is easier especially for beginners to understand when reading test.sav in a hex editor.
_________________
-- Where is he?
-- Who?
-- You know, the human.
-- I think he moved to Tilwick.

#75945 - sajiimori - Fri Mar 17, 2006 5:17 am

No, you're still missing the point. "Char" does not mean "ASCII character". It means "8 bit number", as far as C is concerned. Writing out decimal numbers as sequences of ASCII characters is absurdly complicated compared to just writing binary numbers directly.

Let me put it this way: If you wanted to write the number 1 to memory, would you write the number 49 because it's the ASCII code for the symbol '1', or would you just write the number 1?

#75956 - phoenixj91 - Fri Mar 17, 2006 6:35 am

I understand the concept, really o_0' !
I'm sorry if the terminology I'm using doesn't convey my thoughts, but I get the difference between writing a number and writing the ASCII code for each digit of the number.
[EDIT] Thanks a lot for the code, tepples

#75964 - sajiimori - Fri Mar 17, 2006 7:20 am

Sorry, I was just going by your first reply which implied that you thought I was telling you not to write chars (which I wasn't), and your second reply which implied that you thought the distinction I was making was of type rather than encoding (which it wasn't). Excuse my misunderstanding.