c++: sprintf but return chars. Possible?

Started by
22 comments, last by ApochPiQ 7 years, 11 months ago
If we reinvent std::string, you can get half way there :P

Or, you could just ignore the extra copy and just use std::string.

Here's a c++11 templated version I'm using.


template<class... Args >
std::string makeString(const char* format, Args&&... args) {
  char buffer[256];
  int len = snprintf(buffer, 256, format, std::forward<Args>(args)...);
  if(len >= 256) {
    // if string is too long, try again with a bigger buffer
    char buffer[len + 1];
    snprintf(buffer, len + 1, format, std::forward<Args>(args)...);
    return buffer;
  }
  return buffer;
}

.

Edit: Hmm. Maybe I should read the topic more carefully before answering. Oh well, I'll leave this here anyway. Back to work and getting stuff compiling I guess...

Advertisement

What do you mean "if it fails"?

What i do now with sprintf could then also potentially fail no? I just want to compress the code i need to write. I end up in many such situations (must create a temporary char array that i inject floats and other stuff with %.2f etc and then pass it to a function that takes a "char *" parameter).



The best way to solve this is with a string class of some kind. Otherwise you're going to have a nightmare cleaning up all the heap-allocated temporary strings. Honestly, I think you're pushing the laziness lever a little too hard here. I'd be shocked if your actual coding bottleneck was declaring temporary char arrays.

Wielder of the Sacred Wands
[Work - ArenaNet] [Epoch Language] [Scribblings]

If you're just looking for nice c++ string formatting, I recommend fmt.


fmt (formerly cppformat) is an open-source formatting library. It can be used as a safe alternative to printf or as a fast alternative to C++ IOStreams.

What do you mean "if it fails"?

What i do now with sprintf could then also potentially fail no? I just want to compress the code i need to write. I end up in many such situations (must create a temporary char array that i inject floats and other stuff with %.2f etc and then pass it to a function that takes a "char *" parameter).



The best way to solve this is with a string class of some kind. Otherwise you're going to have a nightmare cleaning up all the heap-allocated temporary strings. Honestly, I think you're pushing the laziness lever a little too hard here. I'd be shocked if your actual coding bottleneck was declaring temporary char arrays.

My suspicion was that the "clutter" and DRY violation was the complaint.

void hurrrrrrrr() {__asm sub [ebp+4],5;}

There are ten kinds of people in this world: those who understand binary and those who don't.

We have a macro for this at work that basically amounts to this (with different names and a lot of extra checks):


#define getChar(fmt, ...) sprintfAndReturnBuffer(_alloca(1024), 1024, fmt, ##__VA_ARGS__)

At the end of the day, you're not getting much. If you want to print a formatted string like that, you're going to have to allocate somehow, and in most cases I'd rather allocate with a real buffer than rely on trivial conveniences like this one.

Well a temp buffer is ok for me, I only use this in specific situations. Not pretty i know but it works:)

Thanks for your input.


char * getStr(const char* fmt, ...) {	
	static char txt[1000];
	va_list va;
	va_start( va, fmt );
	vsprintf( txt, fmt, va );
	va_end( va );
	return txt;
}

I'm not sure that's wise. For example, what do you think this will do?


doStuff2(getStr("Mytext: %d", myInt), getStr("Myothertext: %d", myOtherInt));

If you're okay with nasty surprises -- and I don't recommend being okay with nasty surprises -- your code is fine as-is, but if you want the above code to actually work you need to allocate actual memory instead of a static buffer (and even then, ideally in the calling scope).

Use StringBuilder:


class string_builder {
public:
	template<typename T>
	string_builder& operator << (const T& val) {
		s << val;
		return *this;
	}

	operator const std::string () const {
		return s.str();
	}

private:
	std::ostringstream s;
};


int main(int argc, char* argv[]) {
	try {
		// contrived example
		if ( argc <= 1 ) {
			throw std::runtime_error(
				string_builder() << "Not enough arguments, got " << argc
			);
		}
	}
	catch ( const std::exception& ex ) {
		std::cerr << "Exception caught: " << ex.what() << std::endl;
	}
}
Wait, this isn’t Java?

Use StringBuilder:

<snip>

Is it bad if every time I see the whole IO "<<" overload I vomit in my mouth a little?

Use StringBuilder:

<snip>

Is it bad if every time I see the whole IO "<<" overload I vomit in my mouth a little?

Vomit all you want. I just personally think that "vomit in my mouth a little" is extremely overused. I still manage to keep my stomach acid down when I read it.

This topic is closed to new replies.

Advertisement