space allocation for sprintf()

Chris Torek torek at elf.ee.lbl.gov
Fri Jun 7 02:24:23 AEST 1991


In article <1991Jun5.174543.266 at dg-rtp.dg.com> vook at narnia.rtp.dg.com
(Eric R Vook) writes:
>How do you know how much space to allocate [for sprintf]?
>How do you know when you didn't allocate enough?

A very good question indeed---by which I mean there are no good answers.

The new BSD stdio has snprintf and vsnprintf functions, which take a
buffer length, and guarantee not to overrun that buffer; they both
return the number of characters they would have printed, were the
buffer infinitely long, and thus:

	char small[40], *p = small;
	needed = snprintf(small, sizeof small, "%s%s%s", a1, a2, a3);
	if (needed >= sizeof small) {
		/* the string was truncated */
		p = malloc(needed + 1);
		if (p == NULL) die("malloc failed");
		(void) snprintf(p, needed + 1, "%s%s%s", a1, a2, a3);
	}

Since many uses of sprintf() are simply to transform the arguments into
a set of characters so that those characters can be displayed somewhere
(e.g., a window), the new BSD stdio also provides `funopen', through
which you can open your own analogue to the `write' function.  This
allows you to pass arbitrarily long items through a short buffer.

Of course, none of these are remotely portable.

I have an approximation for a portable `vsnprintf', included below.  It
depends on vfprintf and on `byte' files (hence will not work with fancy
record files such as found on VMS).  It uses open-but-unlinked files
(easily changed, provided you have atexit()).

/*
 * The function we want is called `vsnprintf': sprintf,
 * with output limited to at most some number of bytes.
 * This exists in the `function stdio' library already.
 * Here we roll our own.
 *
 * MAJOR BOGOSITY:  System V stdio has no way to limit the length
 * to an sprintf.  Instead, we use vfprintf to a temp file which we
 * keep open but unlinked.
 */


#include <stdio.h>
#include <varargs.h>

static FILE *
setfil()
{
	register FILE *f;
	char buf[100];

	(void) sprintf(buf, "/tmp/vsnprintf.%d", getpid());
	if ((f = fopen(buf, "w+")) == NULL) {
		perror(buf);
		(void) fprintf(stderr, "cannot set up vsnprintf, help\n");
		exit(1);
	}
	(void) unlink(buf);
	return (f);
}

int
vsnprintf(str, len, fmt, ap)
	char *str;
	size_t len;
	char *fmt;
	va_list ap;
{
	register int nch;
	static FILE *fil;

	if (len == 0)
		return (0);
	if (fil == NULL)
		fil = setfil();
	(void) fseek(fil, 0L, 0);
	nch = vfprintf(fil, fmt, ap);
	(void) fseek(fil, 0L, 0);
	len--;
	if (nch < len)
		len = nch;
	nch = fread(str, 1, len, fil);
	str[nch] = '\0';
	return (nch);
}
-- 
In-Real-Life: Chris Torek, Lawrence Berkeley Lab CSE/EE (+1 415 486 5427)
Berkeley, CA		Domain:	torek at ee.lbl.gov



More information about the Comp.lang.c mailing list