S
Stan Milam
The following code implements a strcat-like function which can receive a
variable number of arguments. I thought it would be faster if I kept a
pointer to the end of the string as it is built so that strcat() would
not always have to find the end of the string as it gets longer and
longer. To test this I called the vstrcat() function with a list of
pointers, then use the regular strcat() function in a loop to build the
same string. After 10,000,000 iteration the regular strcat() won every
time, sometimes by as much as 10 seconds. I've tried several different
approaches (as can be seen with code commented out in the vstrcat()
function) but strcat() always wins. This is using my old DOS C
compiler. On my UNIX machine they are about even.
/**********************************************************************/
/* File Id. vstrcat.c. */
/* Author: Stan Milam. */
/* Date Written: 01 Jun. 92. */
/* Description: */
/* Implement a variardic string concatenation function which will */
/* be much more efficient than successive calls to strcat(). */
/* */
/**********************************************************************/
#include <errno.h>
#include <stddef.h>
#include <string.h>
#include <stdarg.h>
/**********************************************************************/
/* Name: */
/* vstrcat() - Fast, string concatenation. */
/* */
/* Description: */
/* This function receives a variable number of string pointers */
/* and concatenates them together. The only two requirements */
/* is that the first argument which will be the target of the */
/* concatenation must have enough space to contain the entire */
/* concatenated string. The second requirement is the variable */
/* string pointers must be terminated by a NULL pointer. */
/* */
/* Arguments: */
/* char *string - A pointer to a character string where the */
/* remaining character string will be concatenated. */
/* The remaining arguments may vary in number, but must be */
/* pointers to character strings and be NULL terminated. */
/* */
/* Returns: A pointer to the concatenated string. */
/* */
/**********************************************************************/
char *
vstrcat(char *string, ...)
{
if ( string == NULL )
errno = EINVAL;
else {
va_list argptr;
char *end, *wrk;
/**************************************************************/
/* Get the address to the list of pointers. Then find the */
/* initial end of the string. */
/**************************************************************/
va_start(argptr, string);
end = *string == 0 ? string : string + (strlen(string));
/**************************************************************/
/* Pull each pointer from the list and concatenate to the end */
/* and maintain the end of the string throughout. This way */
/* we only count the characters added once. This speeds up */
/* the process tremendously. */
/**************************************************************/
while (!((wrk = va_arg(argptr, char *)) == NULL)) {
/*
strcat( end, wrk );
*/
strcpy( end, wrk );
end += strlen( wrk );
}
va_end(argptr);
}
return string;
}
#ifdef TEST
#include <time.h>
#include "adjust.h"
int
main( void )
{
int x_sub;
long l_sub;
time_t begin, end;
char wrkbuf[1000];
char *wrkarray[] = {
"This is a ",
"bunch of strings ",
"that we will concatenate ",
"very efficiently by always ",
"knowing where the end of the string is going to be. ",
"This makes vstrcat() much ",
"more efficient than successive calls to strcat!",
NULL
};
begin = time(NULL);
for ( l_sub = 0; l_sub < 10000000; l_sub++ ) {
memset(wrkbuf, 0, sizeof(wrkbuf) );
vstrcat(wrkbuf, wrkarray[0],
wrkarray[1],
wrkarray[2],
wrkarray[3],
wrkarray[4],
wrkarray[5],
wrkarray[6],
wrkarray[7],
wrkarray[8]);
}
end = time(NULL);
printf("Total time for %ld iterations of vstrcat(): %ld\n",
l_sub, (long) end - begin);
begin = time(NULL);
for( l_sub = 0; l_sub < 10000000; l_sub++ ) {
memset(wrkbuf, 0, sizeof(wrkbuf) );
for ( x_sub = 0; wrkarray[x_sub]; x_sub++ )
strcat( wrkbuf, wrkarray[x_sub] );
}
end = time(NULL);
printf("Total time for strcat(): %ld\n", (long) end - begin);
return 0;
}
#endif /* TEST */
variable number of arguments. I thought it would be faster if I kept a
pointer to the end of the string as it is built so that strcat() would
not always have to find the end of the string as it gets longer and
longer. To test this I called the vstrcat() function with a list of
pointers, then use the regular strcat() function in a loop to build the
same string. After 10,000,000 iteration the regular strcat() won every
time, sometimes by as much as 10 seconds. I've tried several different
approaches (as can be seen with code commented out in the vstrcat()
function) but strcat() always wins. This is using my old DOS C
compiler. On my UNIX machine they are about even.
/**********************************************************************/
/* File Id. vstrcat.c. */
/* Author: Stan Milam. */
/* Date Written: 01 Jun. 92. */
/* Description: */
/* Implement a variardic string concatenation function which will */
/* be much more efficient than successive calls to strcat(). */
/* */
/**********************************************************************/
#include <errno.h>
#include <stddef.h>
#include <string.h>
#include <stdarg.h>
/**********************************************************************/
/* Name: */
/* vstrcat() - Fast, string concatenation. */
/* */
/* Description: */
/* This function receives a variable number of string pointers */
/* and concatenates them together. The only two requirements */
/* is that the first argument which will be the target of the */
/* concatenation must have enough space to contain the entire */
/* concatenated string. The second requirement is the variable */
/* string pointers must be terminated by a NULL pointer. */
/* */
/* Arguments: */
/* char *string - A pointer to a character string where the */
/* remaining character string will be concatenated. */
/* The remaining arguments may vary in number, but must be */
/* pointers to character strings and be NULL terminated. */
/* */
/* Returns: A pointer to the concatenated string. */
/* */
/**********************************************************************/
char *
vstrcat(char *string, ...)
{
if ( string == NULL )
errno = EINVAL;
else {
va_list argptr;
char *end, *wrk;
/**************************************************************/
/* Get the address to the list of pointers. Then find the */
/* initial end of the string. */
/**************************************************************/
va_start(argptr, string);
end = *string == 0 ? string : string + (strlen(string));
/**************************************************************/
/* Pull each pointer from the list and concatenate to the end */
/* and maintain the end of the string throughout. This way */
/* we only count the characters added once. This speeds up */
/* the process tremendously. */
/**************************************************************/
while (!((wrk = va_arg(argptr, char *)) == NULL)) {
/*
strcat( end, wrk );
*/
strcpy( end, wrk );
end += strlen( wrk );
}
va_end(argptr);
}
return string;
}
#ifdef TEST
#include <time.h>
#include "adjust.h"
int
main( void )
{
int x_sub;
long l_sub;
time_t begin, end;
char wrkbuf[1000];
char *wrkarray[] = {
"This is a ",
"bunch of strings ",
"that we will concatenate ",
"very efficiently by always ",
"knowing where the end of the string is going to be. ",
"This makes vstrcat() much ",
"more efficient than successive calls to strcat!",
NULL
};
begin = time(NULL);
for ( l_sub = 0; l_sub < 10000000; l_sub++ ) {
memset(wrkbuf, 0, sizeof(wrkbuf) );
vstrcat(wrkbuf, wrkarray[0],
wrkarray[1],
wrkarray[2],
wrkarray[3],
wrkarray[4],
wrkarray[5],
wrkarray[6],
wrkarray[7],
wrkarray[8]);
}
end = time(NULL);
printf("Total time for %ld iterations of vstrcat(): %ld\n",
l_sub, (long) end - begin);
begin = time(NULL);
for( l_sub = 0; l_sub < 10000000; l_sub++ ) {
memset(wrkbuf, 0, sizeof(wrkbuf) );
for ( x_sub = 0; wrkarray[x_sub]; x_sub++ )
strcat( wrkbuf, wrkarray[x_sub] );
}
end = time(NULL);
printf("Total time for strcat(): %ld\n", (long) end - begin);
return 0;
}
#endif /* TEST */