Skip to main content
gamedev.net
🔒 Locked

How to write a printf-like function.

Started by kwaung 7 replies 9k views
Original Post
kwaung
kwaung
Hi, I want to write a printf-like function to use as debug-message printing function on my render engine. Anyone can tell me how to write a message printing function that know how to deal with a notation like %d , %f, etc. Thanks in advance.
Zakwayda
Zakwayda
Quote:
Original post by kwaung
Hi,
I want to write a printf-like function to use as debug-message printing function on my render engine. Anyone can tell me how to write a message printing function that know how to deal with a notation like %d , %f, etc.
I or someone else could certainly post the code for this, but if you're programming in C++ you might consider using streams or boost::format instead.
Nypyren
Nypyren
use sprintf. it prints its output to a buffer that you can then use to render.
CrazyCdn
CrazyCdn
Look up these variables/functions in google:
va_list/va_start()/va_end()
"Those who would give up essential liberty to purchase a little temporary safety deserve neither liberty nor safety." --Benjamin Franklin
Adam Hamilton
Adam Hamilton
I have never used this function but I seem to recall the function vsprintf for a purpose such as this. Look it up for how to use it or maybe someone here knows how to use it.

:)
Drew_Benton
Drew_Benton
This example is for educational purposes only. I'd personally consider using another alternative, such as Boost (what jyk mentioned), a printf variation (what Nypyren and Adam Hamilton mentioned), or a premade solution such as Fluid Studio's Logger Class, but if you wish to do it yourself using va_list (what Mike2343 mentioned), then here's an example I made that you should be able to learn from:

// What we need#include <cstdarg>#include <iostream>#include <sstream>#include <string>// Cleaner codeusing std::string;using std::stringstream;using std::cout;string MyPrintf( const char* str, ... ){	// Store the length of the passed in string	int str_size = strlen(str);	// We do not want to process an empty string	if(str_size == 0)		return "";	// This is the delimeter that is used to specify the format flags	// you can use what you want.	static char delim = '%';	// Stores final output, use a stringstream for 	// easy output of all basic data types	stringstream output;	// A place to store the list of arguments	va_list arguments;	// Initializing arguments to store all values after the initial string	va_start(arguments, str);		for(int x = 0; x < str_size; x++)	{		// We know that delim is used to denote a start of a format, but if you		// wanted to use your own character, you'd add it here.		if(str[x] == delim)		{			// If there is a next character, and it is not a delim, ("delimdelim" means add a single delim)			// If you use your own character, replave the % with it!			if(x + 1 < str_size && str[x + 1] != delim)			{				// If we get in a string				if(str[x + 1] == 's')				{					// We have a c-string, so get it and save it					char* temp = va_arg(arguments, char*);					output << temp;					// We know what comes after the delim, so do not process it					x++;				}								// If we get in an integer				else if(str[x + 1] == 'i')				{					// We have an integer, so get it and save it					int temp = va_arg(arguments, int);					output << temp;					// We know what comes after the delim, so do not process it					x++;				}				// ... Continue on for what else you need			}			else if(x + 1 < str_size)			{				// Save the delim that "delimdelim" was used for				output << delim;				// We know what comes after the delim, so do not process it				x++;			}		}		else		{			// Save the character to the output string			output << str[x];		}	}	// Cleans up the list	va_end(arguments);	// Return the actual string	return output.str();}int main(int argc, char* argv[]){	// Create the string	string temp = MyPrintf("Hello %s must be at least %i years old", "world", 100);	// Just show what it is	cout << temp << "\n";	// Standard return	return 0;}


Good luck!
Aardvajk
Aardvajk
Use streams, but if you insist,

#include <stdio.h>#include <stdarg.h>const int max=1024;void debug(const char *s,...){    va_list va; va_start(va,s);    char buffer[max];    sprintf(max,"error: "); vsprintf(max,s,va); sprintf(max,"\n");    va_end(va); do_whatever_with(buffer);}


This will work like printf without having to rewrite formatting code. You should probably also use <cstdio> and <cstdarg> and the std:: thing although if you are using ellipses, this is the least of your worries. You need to take care of buffer overflow as well although this is not easy with the above simple method.
kwaung
kwaung
Thank you guys. I`ll try to write it frist to learn how it work. Thanks again. :)
Enigma
Enigma
If you're using C++ then follow the advice of jyk, Drew_Benton, Herb Sutter and Andrei Alexandrescu (no, the last two of those didn't post in this thread [lol]):
Quote:
C++ Coding Standards by Herb Sutter and Andrei Alexandrescu
98. Don't use varargs (ellipsis).
Quote:
C++ Coding Standards by Herb Sutter and Andrei Alexandrescu
99. Don't use invalid objects. Don't use unsafe functions.
<snip />
Don't use the unsafe C legacy: strcpy, strncpy, sprintf, or any other functions that do write to range-unchecked buffers, and/or do not check and correctly handle out-of-bounds errors.
<snip />

Σnigma

Topic Locked

This topic has been locked by a moderator. New replies are not allowed.

Sign in to reply to this topic.