need better performance than sprintf gives

Posted on 1998-12-21
Last Modified: 2009-07-29
I am writing a C program using Visual C/C++ under NT 4.0. Performance is critical.

Some basic tests indicate that sprintf() is a performance dog.  Are there any other ways to format data that are performance friendly?  

What my code does (at a very high level):  my code loops. Each iteration I process a number of different fields (of various data types: int, long, string, etc), contatenating the formatted results to a single text buffer.

I need to sprintf each field individualy rather than a single sprintf for all the fields because for each iteration of the loop it is not known what fields are involved (in fact, each iteration is likely to have a different set of fields).

What I mean by contatenate.....

  Offset = 0;
  Count = sprintf(Buffer, "%d", int_variable);
  Offset += Count;
  Count = sprintf(Buffer + Offset, "%5ld", long_variable);
  Offset += Count;
  Count = sprintf(Buffer + Offset, "%10s", string_variable);
  Offset += Count;
  Buffer[Offset] = '\n';

Question by:msaccess

Expert Comment

Comment Utility
First, the last line you have:

Buffer[Offset] = '\n';

clobbers the null terminator, and you will most likely end up with garbage at the end of the string.  You may want to add:

Buffer[Offset+1] = '\0';

Now, other that sprintf, you could try converting the numbers to strings using a hand coded itoa function (since the itoa function is not ANSI C).  You could then copy this string to the Buffer string using a loop, but I think that this would actually take longer than the sprintf function.

Also, you mentioned that you could not use a single sprintf function because it would not be known what combination of fields would be used.  If the total number of combinations is realatively small, you might consider using a single sprintf inside a few if .. else control blocks:
  if ( /*field 1 and field 2*/ )
      sprintf( /* field 1 and field 2 */
  else if ( /* field 1 */ )
      sprintf( /* field 1 */)
  /* and so on */
Of course, if there are a number of fields, this quickly becomes impractical.  Hope this helps,


Expert Comment

Comment Utility
I would think the main performance limit of sprintf is parsing the format string.

If you use functions which don't require parsing, this should be faster.

Even these functions can be improved with hand code functions which know exactly what kind of data your working with.

Writing you own itoa is not strictly necessary, there is an MS extension _itoa, but it might worth it.

Before you start coding again, I assume you have used the profiler (or another technique other than guess work) and confirmed that sprintf is really is the function that is slowing your program down.

Expert Comment

Comment Utility
If you think condensing the printf calls to one would help, here is a snippet that might help

// note this is off the top of my head so you may have
// to tweak it a bit, but you get the idea

char *pFmt = NULL;
char *pArgs = NULL; // maybe void* will do

int offset = 0;

// run one iteration to find record size
// allocate enough space for record
pArgs = (char*)malloc( N );
// allocate space for format string at, say 5 x field count
pFmt = malloc( FieldCount * 5)

while(got more fields) {
switch( fieldType ){
      case INT_FIELD:
            strcat(pFmt, "%5d");
            *(int*)(pArgs + offset) = valueOfField;
            offset += sizeof(int);
      case DOUBLE_FIELD:
            strcat(pFmt, "%5.2f");
            *(double*)(pArgs + offset) = valueOfField;
            offset += sizeof(double);
      case ETC:
            do other types
      }      // end switch
}      // end while

// not that strcat can easily be optimized with
// use of an offset and pointer arithmentic as well

// pass the data to vsprintf in one shot
// vsprintf will continue digging into pArgs, as long
// as pFmt specifiers need to be matched.
vsprintf(Buffer, pFmt, pArgs);

LVL 10

Accepted Solution

rbr earned 200 total points
Comment Utility
I think this would be already faster since only one sprintf call is used
sprintf(Buffer, "%d%5ld%10s\n", int_variable,long_variable,string_variable);

Another way is to use itoa and ltoa but they are not ANSI, or you have to write your own function.

my_itoa (char *buffer,int number)
   unsigned int temp;
   char b,*pstart,*pend;
   int i=0;
   if (number=0)
      strcpy (buffer;"0");
   else {
         while (temp > 0) {
     if (number<0)
     for (;i>0;i--,pstart++,pend--) {

Author Comment

Comment Utility
All good and helpful suggestions.  But special thanks to
NullTerminator -- initial indications are that your idea will
help me a great deal.

Thanks to everyone for taking the time to help!!!!

Featured Post

Better Security Awareness With Threat Intelligence

See how one of the leading financial services organizations uses Recorded Future as part of a holistic threat intelligence program to promote security awareness and proactively and efficiently identify threats.

Join & Write a Comment

Suggested Solutions

An Outlet in Cocoa is a persistent reference to a GUI control; it connects a property (a variable) to a control.  For example, it is common to create an Outlet for the text field GUI control and change the text that appears in this field via that Ou…
Windows programmers of the C/C++ variety, how many of you realise that since Window 9x Microsoft has been lying to you about what constitutes Unicode ( They will have you believe that Unicode requires you to use…
The goal of this video is to provide viewers with basic examples to understand opening and writing to files in the C programming language.
The goal of this video is to provide viewers with basic examples to understand and use switch statements in the C programming language.

762 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question

Need Help in Real-Time?

Connect with top rated Experts

12 Experts available now in Live!

Get 1:1 Help Now