*printf and zero size

Started by Bruce Momjianabout 20 years ago6 messages
#1Bruce Momjian
pgman@candle.pha.pa.us

Tom, did you implement this functionality in *printf?

The size may be given as zero to find out how many characters are
needed; in this case, the str argument is ignored. Sprintf() and
vsprintf() effectively assume an infinite size.

Looking at the code it doesn't seem supported. Should it be added to
the limitations comment section?

-- 
  Bruce Momjian                        |  http://candle.pha.pa.us
  pgman@candle.pha.pa.us               |  (610) 359-1001
  +  If your life is a hard drive,     |  13 Roberts Road
  +  Christ can be your backup.        |  Newtown Square, Pennsylvania 19073
#2Tom Lane
tgl@sss.pgh.pa.us
In reply to: Bruce Momjian (#1)
Re: *printf and zero size

Bruce Momjian <pgman@candle.pha.pa.us> writes:

Tom, did you implement this functionality in *printf?
The size may be given as zero to find out how many characters are
needed; in this case, the str argument is ignored. Sprintf() and
vsprintf() effectively assume an infinite size.

Where do you read that? The SUS says the opposite:

If the value of n is zero on a call to snprintf(), an unspecified
value less than 1 is returned.

and that's what our code implements.

regards, tom lane

#3Bruce Momjian
pgman@candle.pha.pa.us
In reply to: Tom Lane (#2)
Re: *printf and zero size

Tom Lane wrote:

Bruce Momjian <pgman@candle.pha.pa.us> writes:

Tom, did you implement this functionality in *printf?
The size may be given as zero to find out how many characters are
needed; in this case, the str argument is ignored. Sprintf() and
vsprintf() effectively assume an infinite size.

Where do you read that? The SUS says the opposite:

If the value of n is zero on a call to snprintf(), an unspecified
value less than 1 is returned.

and that's what our code implements.

I got it from the BSD/OS manual page, and in the NetBSD manual page I
see:

If size is zero, nothing is written and str may be a NULL pointer.

and:

Upon successful completion snprintf() and vsnprintf() return the number
of characters that would have been written to a sufficiently sized str,
excluding the terminating NUL character.

but it seems this is some BSD'ism that we don't need to support if the
standard doesn't say so.

-- 
  Bruce Momjian                        |  http://candle.pha.pa.us
  pgman@candle.pha.pa.us               |  (610) 359-1001
  +  If your life is a hard drive,     |  13 Roberts Road
  +  Christ can be your backup.        |  Newtown Square, Pennsylvania 19073
#4Tom Lane
tgl@sss.pgh.pa.us
In reply to: Bruce Momjian (#3)
Re: *printf and zero size

Bruce Momjian <pgman@candle.pha.pa.us> writes:

Upon successful completion snprintf() and vsnprintf() return the number
of characters that would have been written to a sufficiently sized str,
excluding the terminating NUL character.

but it seems this is some BSD'ism that we don't need to support if the
standard doesn't say so.

Yeah, that is a BSD-ism. You have a point though, we ought to document
which return convention the code follows. I'll add something.

regards, tom lane

#5Kurt Roeckx
kurt@roeckx.be
In reply to: Bruce Momjian (#3)
Re: *printf and zero size

On Mon, Dec 05, 2005 at 04:35:31PM -0500, Bruce Momjian wrote:

but it seems this is some BSD'ism that we don't need to support if the
standard doesn't say so.

I think the Linux manpage is more informative about this:

The functions snprintf and vsnprintf do not write more than
size bytes (including the trailing '\0'). If the output was truncated
due to this limit then the return value is the number of characters
(not including the trailing '\0') which would have been written to the
final string if enough space had been available. Thus, a return value
of size or more means that the output was truncated. (See also below
under NOTES.) If an output error is encountered, a negative value is
returned.

[...]

NOTES
The glibc implementation of the functions snprintf() and vsnprintf()
conforms to the C99 standard, i.e., behaves as described above, since
glibc version 2.1. Until glibc 2.0.6 they would return -1 when the out-
put was truncated.

[...]

Concerning the return value of snprintf(), the SUSv2 and the C99 stan-
dard contradict each other: when snprintf() is called with size=0 then
SUSv2 stipulates an unspecified return value less than 1, while C99
allows str to be NULL in this case, and gives the return value (as
always) as the number of characters that would have been written in
case the output string has been large enough.

Kurt

#6Tom Lane
tgl@sss.pgh.pa.us
In reply to: Kurt Roeckx (#5)
Re: *printf and zero size

Kurt Roeckx <kurt@roeckx.be> writes:

Concerning the return value of snprintf(), the SUSv2 and the C99 stan-
dard contradict each other:

Is that where the problem comes from?

Anyway, I've added some text to snprintf.c explaining what we do. Since
the calling code has to be prepared to handle either result convention,
I see no need to do anything except what's easiest to implement, which
in this case is the SUS behavior. (There's also a consistency issue,
which is that fprintf is supposed to return the number of bytes actually
transmitted, not the number it would have sent in the absence of error.)

regards, tom lane

   * 5. Space and '#' flags are not implemented.
+  *
+  *
+  * The result values of these functions are not the same across different
+  * platforms.  This implementation is compatible with the Single Unix Spec:
+  *
+  * 1. -1 is returned only if processing is abandoned due to an invalid
+  * parameter, such as incorrect format string.  (Although not required by
+  * the spec, this happens only when no characters have yet been transmitted
+  * to the destination.)
+  *
+  * 2. For snprintf and sprintf, 0 is returned if str == NULL or count == 0;
+  * no data has been stored.
+  *
+  * 3. Otherwise, the number of bytes actually transmitted to the destination
+  * is returned (excluding the trailing '\0' for snprintf and sprintf).
+  *
+  * For snprintf with nonzero count, the result cannot be more than count-1
+  * (a trailing '\0' is always stored); it is not possible to distinguish
+  * buffer overrun from exact fit.  This is unlike some implementations that
+  * return the number of bytes that would have been needed for the complete
+  * result string.
   */