Advertisement Jump to content
Sign in to follow this  
OpOpOpOp

[C++] Is there an easy way to mimic printf()'s behavior?

This topic is 1743 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Recommended Posts

Topic title says it all. I would like to turn this mess:

char string[100];
sprintf(string, "Error: %s at %08X with parameter %i and size %.2f", szA, pB, iC, fD);
pretty_fatal_error_thrower(string);

into this beauty:

pretty_fatal_error_thrower("Error: %s at %08X with parameter %i and size %.2f", szA, pB, iC, fD);

Can it be done without basically re-writing printf() from scratch? That's pretty much all I get with a Google search. I would switch to C++ streams except for the minuscule yet important detail that streaming does not support custom formatting such as "%08X". Thanks in advance.

Share this post


Link to post
Share on other sites
Advertisement

Is printf not ok?

 

I think he wants to automatically do other things when that function is called in addition to printf'ing (like wrapping the function) so, yeah, a variadic function with vsprintf - or a variadic macro - would be the usual way to do this in C99 as Hodgman suggested, and of course if you go C++ there's probably plenty of alternatives.

Share this post


Link to post
Share on other sites

I used to work at a company called Tao. In the four years I was there, not a single day went by without an active bug being logged on printf. smile.png

 

I would switch to strings and write my own hex formatting code for that one case.

Share this post


Link to post
Share on other sites

Perhaps this would work:

	char str[255];

 

The core problem with using a C-style printf is that you have to either guess at the length of the resulting string or use one of the "safe" sized variants of printf and attempt with larger and larger buffers until the resulting string fits.

 

This is more pretty_fatal_stack_smash than pretty_fatal_message_format.

Share this post


Link to post
Share on other sites

In addition to Zao's points, you also have no type safety and can easily supply a parameter list that does not match the format string.

 

Here's a really naive header I use to provde type-safe string building. You could extend this easily enough:

#ifndef STRINGFORMAT_H
#define STRINGFORMAT_H

#include <string>
#include <sstream>

template<class T0, class T1, class T2, class T3, class T4, class T5, class T6, class T7, class T8> std::string stringFormat(const T0 &t0, const T1 &t1, const T2 &t2, const T3 &t3, const T4 &t4, const T5 &t5, const T6 &t6, const T7 &t7, const T8 &t8)
{
    std::ostringstream os;
    os << t0 << t1 << t2 << t3 << t4 << t5 << t6 << t7 << t8;

    return os.str();
}

template<class T0, class T1, class T2, class T3, class T4, class T5, class T6, class T7> std::string stringFormat(const T0 &t0, const T1 &t1, const T2 &t2, const T3 &t3, const T4 &t4, const T5 &t5, const T6 &t6, const T7 &t7){ return stringFormat(t0, t1, t2, t3, t4, t5, t6, t7, ""); }
template<class T0, class T1, class T2, class T3, class T4, class T5, class T6> std::string stringFormat(const T0 &t0, const T1 &t1, const T2 &t2, const T3 &t3, const T4 &t4, const T5 &t5, const T6 &t6){ return stringFormat(t0, t1, t2, t3, t4, t5, t6, ""); }
template<class T0, class T1, class T2, class T3, class T4, class T5> std::string stringFormat(const T0 &t0, const T1 &t1, const T2 &t2, const T3 &t3, const T4 &t4, const T5 &t5){ return stringFormat(t0, t1, t2, t3, t4, t5, ""); }
template<class T0, class T1, class T2, class T3, class T4> std::string stringFormat(const T0 &t0, const T1 &t1, const T2 &t2, const T3 &t3, const T4 &t4){ return stringFormat(t0, t1, t2, t3, t4, ""); }
template<class T0, class T1, class T2, class T3> std::string stringFormat(const T0 &t0, const T1 &t1, const T2 &t2, const T3 &t3){ return stringFormat(t0, t1, t2, t3, ""); }
template<class T0, class T1, class T2> std::string stringFormat(const T0 &t0, const T1 &t1, const T2 &t2){ return stringFormat(t0, t1, t2, ""); }
template<class T0, class T1> std::string stringFormat(const T0 &t0, const T1 &t1){ return stringFormat(t0, t1, ""); }
template<class T0> std::string stringFormat(const T0 &t0){ return stringFormat(t0, ""); }

#endif // STRINGFORMAT_H

Usage

class SomeClass
{
};

// implement ostream overload for SomeClass

SomeClass c;
std::string s = stringFormat("There are ", 0.24f, " things and ", c, " works too");

You can just std::cout the result and throw your exception instead of returning the string. I'm sure better, more extensible ways of doing this now with varadic template args exist but they are beyond me at present.

Edited by Aardvajk

Share this post


Link to post
Share on other sites
Sign in to follow this  

  • Advertisement
×

Important Information

By using GameDev.net, you agree to our community Guidelines, Terms of Use, and Privacy Policy.

GameDev.net is your game development community. Create an account for your GameDev Portfolio and participate in the largest developer community in the games industry.

Sign me up!