• Status: Solved
  • Priority: Medium
  • Security: Public
  • Views: 1615
  • Last Modified:

need better performance than sprintf gives

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';

0
msaccess
Asked:
msaccess
1 Solution
 
marcjbCommented:
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,

Marc
0
 
Answers2000Commented:
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.
0
 
NullTerminatorCommented:
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);
            break;
      case DOUBLE_FIELD:
            strcat(pFmt, "%5.2f");
            *(double*)(pArgs + offset) = valueOfField;
            offset += sizeof(double);
            break;
      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);

'\0'
0
 
rbrCommented:
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.
e.g.

my_itoa (char *buffer,int number)
{
   unsigned int temp;
   char b,*pstart,*pend;
   int i=0;
   if (number=0)
      strcpy (buffer;"0");
   else {
         temp=abs(number)
         while (temp > 0) {
                  buffer[i++]='0'+temp%10;
            temp/=10;
         }
     if (number<0)
            buffer[i++]='-';
      buffer[i]=0;
     pstart=buffer;
     pend=&(buffer[i-1]);
      i/=2;
     
     for (;i>0;i--,pstart++,pend--) {
        b=*pstart
        *pstart=*pend;
        *pend=b;
      }
}      
       
0
 
msaccessAuthor Commented:
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!!!!
0

Featured Post

Concerto Cloud for Software Providers & ISVs

Can Concerto Cloud Services help you focus on evolving your application offerings, while delivering the best cloud experience to your customers? From DevOps to revenue models and customer support, the answer is yes!

Learn how Concerto can help you.

Tackle projects and never again get stuck behind a technical roadblock.
Join Now