How can one implement printf-like functionality in assembler?
I'm very much just looking for feedback and guidance rather than a direct ans开发者_JAVA技巧wer.
Using the .586
assembler instructions, how can you simulate printf-like functionality? For fixed width fields, I know I could do something like this:
.data
Format BYTE 'You are ## years old.',0
And then before printing the string, simply replace the ## values to the appropriate number, changing them back afterwards in case I need to use the format string multiple times with different values.
This might not be the best way, but for now it works.
What I can't figure out is how to do it if you don't know the number of digits ahead of time. The format option is okay if you know the maximum number of digits you want to use (above example won't work pretty-like for people 100 years old and older, you lose the spaces between words).
If you reserve too much space though, you get double spaces between your number and your worlds.
.data
Format BYTE 'You are ### years old.',0
Using my scheme with someone who is 12 would produce:
You are 12 years old.
My only thought was is there happened to be an ASCII character which printed nothing (aside from \0
), but it seems tacky.
The whole problem arises because the instructor wants us to be able to print this type of formatted string using a single call to a PrintString procedure (which he provided us) which looks for esi
to be set to a \0
terminated byte array.
You are assuming that your output will be into the same buffer that's used to specify the formatting - the C printf()
routines don't do that. Also realize that the conversion caused by a format specifier doesn't need to take up the same number of characters in the output as the format specifier. For example, the printf()
specifier %s
can take up far more than 2 characters in the output (or can use fewer than 2 characters).
You can have your assembly routine do the same thing that the C routines do - the format string is input to the function (and isn't modified) as are the items to be converted as specified by the format string. The output produced by the function goes somewhere else - either to an output routine that sends the data to a file or device, or to a memory buffer provided by the caller.
As the function walks the format string, it can decide if the characters need to go into the output unchanged (ie., the characters in the format string that aren't a format specifier). When it comes to a format specifier, it will consume another input parameter, convert it according to the format specifier, and send those characters to the output.
Well, you should be able to calculate the number of digits that you need at runtime. Then you have a number of alternatives:
Allocate the maximum space beforehand, and then shift left-wards parts of your string so that no extra spaces are left.
Use only a single space, and then extend & shift your string right-wards to add more space as needed. I think you'd have a few memory management issues with this, though...
First define your escape sequences for each data type, e.g "%f", and put them into a table of key-value pairs. Then split the task up into the following subroutines:
An indexOf routine, that takes a pointer to the string buffer, and a starting index. It searches for one of the escape sequences that you defined from the starting index, and returns the index of it if the escape sequence is found or -1 if none are found.
A print function for each data type, one for integers, unsigned ints, floats, etc...that takes the data by value and prints it to the screen.
The printf function takes a pointer to a string buffer and the data to be inserted and prints it to the screen.
In printf, make a loop that searches for an escape sequence with indexOf. If found, print the source string up until the index returned by indexOf. Identify the data type with your table, then print the data with the corresponding print function. Start the loop again searching from the new index after the escape sequence. Loop until you reach the end of the source string. Done. No need to dynamically allocate any memory.
精彩评论