posprintf Documentation

What is it?

posprintf is a function you can call in your Gameboy Advance programs to generate strings. It is basically a somewhat amputated version of the standard C library function, sprintf.

Why use it?

Probably the most significant use of it is to print out and format numbers for display on the screen. In order to do this, the numbers need to be converted from their internal representation (base 2) to decimal (base 10). posprintf uses an extremely efficient algorithm scammed off of the 'net to do this, and it is written entirely in Thumb assembler to run very quickly (without consuming the internal memory needed to run efficiently in ARM mode).

Other reasons to use it include that it's fast, extremely flexible for most GBA applications, and absolutely free. I wouldn't say no to a credit if it is used in an application, though, commercial or otherwise.

How do I use it?

  1. Include the file posprintf.h in your C source code that you want to call the function. (ie. #include "posprintf.h")

  2. Call it the same way you would call sprintf, keeping in mind the differences between the two (see the next section).

  3. Make sure to link the file posprintf.o with your project. Generally this just means including posprintf.o on the command line when you call gcc.

That's all there is to it.

How do I call the function?

The syntax is as follows:

posprintf(char *dest, const char *src[, param1[, param2[, ... paramN]]]);

Format Specifiers

The following are valid format specifiers for use with posprintf:

Output Control

The output of %d, %l, %x and %X tags may optionally be influenced by the following prefixes:

Note: If the number printed is negative, then the negative sign will consume a leading space/zero, if there are any.

Other Notes

Optimized for GBA development

One of the big realizations in understanding this code is that few GBA games need to display numbers larger than 65,535, and when they do these are the minority of numbers, not the majority. The %d specifier is highly optimized to work with 16 bits, and you should use it whenever possible.

For the minority of occasions when you need to display more than 16 bits worth of numerical data, %l works fine to numbers well beyond the plus-or-minus 500 million mark. (The actual limit is +/- 655,359,999.) It takes about twice as long to run as %d, though, and includes a slow SWI call to split the number into two chunks, so you should still use %d instead whenever you can.

If you need to display numbers larger than 500 million, then you will either have to heavily alter the code, use a different utility, or break your number up into sizeable chunks. If you do need to display larger numbers than 500 million for a GBA game, though, you may want to rethink your game design.

What about other ARM machines?

Although posprintf is mostly written as generic Thumb code, the %l (29-bit print) specifier code currently uses a software interrupt (SWI) specific to the Gameboy Advance to perform a division. If you wish to port this to other ARM machines, you may need to alter this code. I believe that most ARM machines support SWI 7 as an alternative software divide, although you will have to swap the numerator/denominator registers (r0 and r1).

Can't you optimize out the SWI call? Use inverse multiplication, register shifting, or somesuch?

Not easily. Not in Thumb mode, anyway, which doesn't have the 64-bit multiply instruction. The number has many significant digits, and is being divided by 10,000, which requires two registers to keep things accurate. My best advice is to avoid it in the first place by keeping your numbers small and using %d instead, but also not to fret over using %l as the SWI is only issued once in the entire routine, and everything else is still quite zippy. It is not like you will have to call it a bazillion times per frame, and it's still a helluva lot faster than what the standard library sprintf does. If anyone does feel like optimizing this, though, please send me the results.

If it's displaying 16-bit numbers and they are signed, shouldn't they only be in the range +/- 32767?

The conversion to base 10 is actually done on the number unsigned, so you get a full range up to 65,535. The sign is taken from the extension of the number to 32 bits, which happens automatically regardless of whether you pass a short or not. The same applies to %l.

What are the terms and restrictions to using posprintf?

posprintf no longer has a license; it is freely available to use as part of the public domain.

Why "posprintf"?

I think the "po" stood for something originally, but now the "pos" is just a play on my last name. Please, no P.O.S. jokes. :)

Contacting the Author

Please submit all bug reports, queries, suggested improvements, etc. to Dan Posluns at dan@danposluns.com.