Printing To Screen: Difference between revisions
Jump to navigation
Jump to search
[unchecked revision] | [unchecked revision] |
Content deleted Content added
→Printing Integers: '''If''' we provide example code, we could just as well go the full distance. ;-) |
→Printf: The explanations were not enough to base a stdarg.h implementation upon them, factually not quite correct, and as such probably more confusing than helpful. |
||
Line 105: | Line 105: | ||
== Printf == |
== Printf == |
||
If you're working with C, you may want to print any number of arguments |
If you're working with C, you may want to print any number of arguments, like <tt>printf()</tt> does. For this, you need to handle variable argument lists. Looking at the <tt>stdarg.h</tt> file from other operating systems (e.g. Linux 0.1), you might be a bit confused by the macro definitions in that file, as they are basically black magic depending on the C calling conventions. As such, they are not exactly portable. |
||
The good news are that <tt>stdarg.h</tt> is part of a freestanding implementation, so you can #include it even from your kernel source files. Under [[GCC]], the following simple implementation uses the gcc's built-in functionality to do all the work for you: |
|||
<tt>va_start()</tt> points to the first variable argument. |
|||
<tt>va_arg()</tt> advances the pointer, then evaluates to the previous argument (comma operator). |
|||
<tt>va_end()</tt> doesn't do anything. |
|||
The good news are that stdagr.h is part of the required features for freestanding implementations, so you can #include it even from your kernel source files. |
|||
'''Example:''' |
|||
To implement <tt>va_start()</tt>, you extract the address of the last 'known' argument and advance (yes, it's a <tt>+</tt> since you're rewinding the stack) to the next stack item. The voodoo comes to the fact that things are automatically aligned on 32bits boundary on the stack, even if just 1 byte. This approach however only works on x86 and also depends on the calling convention. Some calling conventions like fastcall, or on other architectures like x86-64 this approach doesn't work because the parameters are passed in registers and/or stack. Under [[GCC]], the following simple implementation uses the gcc's built-in functionality to do all the work for you: |
|||
<pre> |
<pre> |
||
#define va_start(v,l) __builtin_va_start(v,l) |
#define va_start(v,l) __builtin_va_start(v,l) |
||
Line 124: | Line 117: | ||
</pre> |
</pre> |
||
⚫ | |||
Not using those, <tt>va_arg()</tt> requires a bit more black magic since you have two things to do: |
|||
* advance to the next item |
|||
* return the value of the (previously current) item |
|||
⚫ | |||
Solar's [http://pdclib.rootdirectory.de Public Domain C Library] has those implementations as well. |
|||
== Troubleshooting == |
== Troubleshooting == |