writing alibrary funtion ssprintf()

J

jitu.csewizard

hi

overview:
function sprintf(<buffername>,<format string>, .....)
in this function you need to allocate the size of buffername before
hand.

question:
function ssprintf(<buffername>,<format string>, .....)
i need to write a funtion in time and space optimized way so that i
should allocate buffername after getting the string.(ignore the time of
mallocing the memory...there is a different strategy for mallocing...it
won't take much time)
i have thought of a strategy:
1. writing the format string to /dev/null or to memory and get the
length of the string and then again malloc(not exactly malloc ....there
is a different optimized strategy) the required string.
problem: a call to printf takes time if the string is long
note:calling string functions like strlen also takes time.
can you suggest me a better optimized strategy.
 
D

Diomidis Spinellis

question:
function ssprintf(<buffername>,<format string>, .....)
i need to write a funtion in time and space optimized way so that i
should allocate buffername after getting the string.(ignore the time of
mallocing the memory...there is a different strategy for mallocing...it
won't take much time)
i have thought of a strategy:
1. writing the format string to /dev/null or to memory and get the
length of the string and then again malloc(not exactly malloc ....there
is a different optimized strategy) the required string.
problem: a call to printf takes time if the string is long
note:calling string functions like strlen also takes time.
can you suggest me a better optimized strategy.

A portable approach would involve allocating a buffer with a default
large size, and calling snprintf and (your) realloc on it. Snprintf
will return the size of the buffer required for printing the whole
string, so you can always adjust the default size upwards to match that
number, and keep it that way in subsequent calls. For the first few
calls your implementation will call snprintf multiple times to establish
the size needed, but this overhead will be amortized over time.

One other more cumbersome approach is to take an open-source sprintf
implementation and modify it to make it work in the way you want. You
will find that most printf implementations keep track of the size of the
resulting string, in order to implement functions like snprintf. For
example, the FreeBSD/NetBSD implementation keeps the distinct elements
to be printed in an iov vector of output objects, and tallies their
length. This is done by a call to a PRINT macro for each distinct element.

#define PRINT(ptr, len) { \
iovp->iov_base = (ptr); \
iovp->iov_len = (len); \
uio.uio_resid += (len); \
iovp++; \
if (++uio.uio_iovcnt >= NIOV) { \
if (__sprint(fp, &uio)) \
goto error; \
iovp = iov; \
} \
}

You can thus take uio.uio_resid and use it to allocate the string's
buffer, before flushing the buffer to it. For an example on how this is
done, look at the FreeBSD asprintf implementation, which allocates the
buffer memory with malloc.

A different (non-portable) approach is to create an stdio object that
will write to a dynamically growing buffer. Nowadays many stdio
implementations are object-oriented, and provide you a (non-portable and
sometimes undocumented) way to supply your own underlying I/O functions.
For example, the FreeBSD implementation's fwopen function takes as an
argument a pointer to a write function.

FILE *fwopen(void *cookie, int (*writefn)(void *, const char *, int));

I assume that your optimized malloc implementation can grow objects
dynamically. If not, look at the GNU Obstack facility
<http://gcc.gnu.org/onlinedocs/libiberty/Growing-Objects.html#Growing-Objects>.

Also, keep in mind that I/O processing is seldom a program's bottleneck:
the underlying I/O operations (for example disk writes) are orders of
magnitude more expensive. Therefore be sure to profile your program to
establish the need for implementing the more exotic solutions I described.
 
W

websnarf

overview:
function sprintf(<buffername>,<format string>, .....)
in this function you need to allocate the size of buffername before
hand.

question:
function ssprintf(<buffername>,<format string>, .....)
i need to write a funtion in time and space optimized way so that i
should allocate buffername after getting the string.(ignore the time of
mallocing the memory...there is a different strategy for mallocing...it
won't take much time)
i have thought of a strategy:
1. writing the format string to /dev/null or to memory and get the
length of the string and then again malloc(not exactly malloc ....there
is a different optimized strategy) the required string.
problem: a call to printf takes time if the string is long
note:calling string functions like strlen also takes time.
can you suggest me a better optimized strategy.

You can see the Better String Library ( http://bstring.sf.net/ ) for an
implementation of how to do this in the bformat() function. Basically
you leverage the compiler's vsnprintf capabilities as much as possible,
to determine the length and then allocate and output to the result in a
final pass. For compilers that don't have a compliant vsnprintf, they
usually have a variant with which you can do the operation over and
over again for predetermined lengths guessed in a sequence of powers of
2 to zero in on the correct length.

As an alternative, yes, you can use vfprintf, then determine the size
of the output file, however, this assumes you have disk space, write
access, etc and its insanely slow.

Of course an alternative is to get the source for a portable snprintf (
http://www.ijs.si/software/snprintf/ ) and hack on the code to make it
do what you want.
 
M

Michael Wojcik

A portable approach would involve allocating a buffer with a default
large size, and calling snprintf and (your) realloc on it. Snprintf
will return the size of the buffer required for printing the whole
string, so you can always adjust the default size upwards to match that
number, and keep it that way in subsequent calls.

Note this requires an snprintf that conforms to C99 (or another
standard that specifies Chris Torek's New Improved snprintf Return
Semantics [TM]; I think they might have been required by POSIX prior
to 1999). Earlier versions of snprintf were not required to return
the formatted length of the string if the buffer was too small.

I know of three fairly prominent implementations which are broken in
this regard: Compaq C for Tru64, HP C for HP-UX, and most importantly
Microsoft Visual C++ (when using its C implementation, of course). I
suspect the most recent Compaq/HP products have been fixed (because I
believe they now claim C99 compliance), but I believe MSVC is still
broken. (Note that MSVC technically does not supply an snprintf
implementation; they supply something called _snprintf, which is
almost but not quite completely unlike tea. Microsoft's approach to
improving C's string handling has been to invent their own APIs and
then try to force them on everyone else.)

All of these return -1 for any failure, whether its a malformed
format string or a too-short buffer.

Consequently, the portability of any solution involving snprintf has
quite a caveat: it only applies to implementations with conforming
snprintf, and there are notable exceptions.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,778
Messages
2,569,605
Members
45,238
Latest member
Top CryptoPodcasts

Latest Threads

Top