string print methods

If I write Serial.print(somevar);

Whatever type and value somevar happens to be, get’s formatted as a string representation and sent to the Serial port.

So, what if I want to do essentially the same thing but target a memory buffer, instead of a hardware device.

On a desktop, I would just use sprintf but I keep reading it is a poor and costly way of doing things.

Anyone know of a straightforward formatting routine which is Arduino friendly, a library routine perhaps?

MattS-UK:
On a desktop, I would just use sprintf but I keep reading it is a poor and costly way of doing things.

Where are you reading that?

sprintf() is the first thing I would recommend.

The standard library function sprintf() is not inefficient, it's just that it can do so many things its an H-bomb-to-kill-an-ant if you just want to print out the contents of a variable. While I haven't done any size comparisons, my guess is that sprintf() would use more code space that just a simple print statement would.

Thanks Arrch

I'm still trying to adapt my coding technique to the tiny amount of RAM available and I'm just a little nervous.

I read quite a few things but I guess the following post from the forum sums up my confusion.
http://forum.arduino.cc/index.php/topic,131289.0.html
I didnt' think it was made clear in the post, whether sprintf is safe or not, preferred or supported or not.

MattS-UK:
I read quite a few things but I guess the following post from the forum sums up my confusion.
http://forum.arduino.cc/index.php/topic,131289.0.html
I didnt' think it was made clear in the post, whether sprintf is safe or not, preferred or supported or not.

Are you sure that is the right link?

There is nothing in that thread that suggests that sprintf() is poor or costly.

MattS-UK:
So, what if I want to do essentially the same thing but target a memory buffer, instead of a hardware device.

Seemed like a nice idea, especially if sprintf is costly. So here is my gift to you.

This is my proposal:

class MemPrinter : public Print{
	public:
		template< typename T > 
			explicit MemPrinter( const T *u_DataPtr ) : Data( ( uint8_t* ) u_DataPtr ) 
				{ return; }
	protected:
	
		size_t write(const uint8_t *buffer, size_t size)
			{
				const size_t s_Return = size;
				while( size-- ) *this->Data++ =  *buffer++;
				return s_Return;
			}
		
		size_t write(uint8_t u_Data )
			{ 
				*this->Data++ = u_Data;
				return 0x01; 
			}
			
	private:
	
		uint8_t *Data;
};

It contains all the print/ln functionality of the serial library ( mostly untested ).
Heres how it works:

//Create a buffer
char buffer[ 16 ];

//Recommend clearing buffers located on the stack ( may be filled with rubbish data )
memset( buffer, 0x00, 16 ); //Not required for MemPrinter use.

//Class in action.
MemPrinter( buffer ).print( 123.45678f );

//Print result to see
//Serial.print( buffer );

MemPrinter( buffer ).print( 123.45678f, 5 );
//Serial.print( buffer );

I posted a more complete library of my code above incase anyone may find it useful: String lib alternative / Print class targeting memory.

Arrch:
There is nothing in that thread that suggests that sprintf() is poor or costly.

That's not the thread you're looking for!

Sorry, my bad, I meant this one
http://forum.arduino.cc/index.php/topic,40790.0.html

4th post down, I started worrying.

Thanks for sharing Pyro.
I will most definitely be giving your code a go.

Pyro:
Have you checked to see if your libraries footprint is less than sprintf()?

MattS-UK:

Arrch:
There is nothing in that thread that suggests that sprintf() is poor or costly.

That’s not the thread you’re looking for!

Sorry, my bad, I meant this one
http://forum.arduino.cc/index.php/topic,40790.0.html

4th post down, I started worrying.

Whether or not it’s “costly” really depends on what you are doing with it. If all you need to do is convert a number to its ASCII representation and put it in a string, then itoa() would be the easiest. If, however, you then need to take that ASCII number and combine it with another constant string or other ASCII numbers, then sprintf() is the best way to do it. The extra ~1.6KB in program memory isn’t going to be a problem unless you are right up against the limit in terms of program memory. You’re much more likely to run out of SRAM before your run out of program memory, though.

If you’re really concerned about efficiency, you can write the algorithm our yourself for your specific use.

KeithRB:
Pyro:
Have you checked to see if your libraries footprint is less than sprintf()?

No, but you will gain performance if you are using the print class anywhere else, such as 'Serial' or an LCD class. This is due to it sharing the same functionality, whereas sprintf may result in an additional algorithm for the same task done by Serial.

After a little testing, it seems quite an improvement over sprintf.
sprintf had an overhead of 1758 bytes, the Print class was only 816 bytes.

Below is a sketch using the code posted here
Test number 1 to 3 should compile the same size, test 0 is sprintf.
Floating point numbers are not included in this test as sprintf does not support them, whereas the print class handles floats fine.

#include <GENX.h>

//Modify this
#define TEST_NUMBER 0

void setup(){
  
  char buffer[ 64 ];
  
  Serial.begin( 115200 );
  
  #if TEST_NUMBER == 0
  
    sprintf( buffer, "sprintf integer copy test: %d", analogRead( 0 ) );
    Serial.print( buffer );
    
  #elif TEST_NUMBER == 1
  
    GString g( buffer );
    g += "sprintf integer copy test: ";
    g += analogRead( 0 );
    Serial.print( g );
  
  #elif TEST_NUMBER == 2
  
    GString g( buffer );
    g.print( "sprintf integer copy test: " );
    g.print( analogRead( 0 ) );
    Serial.print( g );  
  
  #elif TEST_NUMBER == 3
  
    Serial.print( GString( buffer ).concat( "sprintf integer copy test: " ).concat( analogRead( 0 ) ) );  
  
  #endif
}

void loop(){}

MattS-UK:
I'm still trying to adapt my coding technique to the tiny amount of RAM available and I'm just a little nervous.

Using sprintf() only impacts RAM in the size of the string array you print to. The code goes to flash memory (which you have far more of, but that can get tight too), not RAM.