max size for printf() format conversion?

M

Matt Garman

Is there a clean, portable way to determine the maximum value of
converted numerical fields with printf()-like functions? Doing this
at compile-time would be preferable.

For example, %i should never convert to a string that is longer than
the number of digits in INT_MAX, right?

I'd like to create a structure that contains character
representations of numerical types (e.g., instead of storing 3421 as
an int, it would store the char array "3421"). I'd like to make
these fields a fixed-size static array, but obviously I don't want
to make them too small.

Thanks!
Matt
 
J

Jens.Toerring

Matt Garman said:
Is there a clean, portable way to determine the maximum value of
converted numerical fields with printf()-like functions? Doing this
at compile-time would be preferable.
For example, %i should never convert to a string that is longer than
the number of digits in INT_MAX, right?

Two points: INT_MAX and INT_MIN could differ by more than one, so
to be on the save side you would have to take into account both if
you use the values of these limits. And for negative values you
would have to add one for the minus sign.
I'd like to create a structure that contains character
representations of numerical types (e.g., instead of storing 3421 as
an int, it would store the char array "3421"). I'd like to make
these fields a fixed-size static array, but obviously I don't want
to make them too small.

If my calculations aren't wrong you should be on the safe side with

#defined MAX_INT_LENGTH ( ( sizeof( int ) * CHAR_BIT + 1 ) / 3 + 1 )

(both for signed and unsigned ints, you can drop the final "+ 1" for
unsigned ints). This can be evaluated at compile time and should be
portable.
Regards, Jens
 
M

Michael Mair

Matt said:
Is there a clean, portable way to determine the maximum value of
converted numerical fields with printf()-like functions? Doing this
at compile-time would be preferable.

For example, %i should never convert to a string that is longer than
the number of digits in INT_MAX, right?

I'd like to create a structure that contains character
representations of numerical types (e.g., instead of storing 3421 as
an int, it would store the char array "3421"). I'd like to make
these fields a fixed-size static array, but obviously I don't want
to make them too small.

C89: The draft I use states that a single conversion can produce a
maximum of at least 509 characters.
C99 (standard): This limit goes up to 4095 characters.

If in doubt, use snprintf()/vsnprintf() if available (and malloc()).

Cheers
Michael
 
K

Keith Thompson

Michael Mair said:
C89: The draft I use states that a single conversion can produce a
maximum of at least 509 characters.
C99 (standard): This limit goes up to 4095 characters.

Right, but I don't think that's what he's looking for. A C99
implementation isn't required to limit printf output to 4095
characters, so you can't assume that

char buf[4096];
sprintf(buf, some_format, arg1, arg2, arg3);

won't overflow the buffer.

A function that would take a format string and return the maximum
possible length of the output it can generate would solve the problem.
If the format string contains "%s", of course, the result is limited
only by the possible length of a string. The limit for "%d" would
typically be 6 on a system with 16-bit int, 11 on a system with 32-bit
int. Floating-point formats are a bit more challenging. The limit
for "%p" is difficult or impossible to determine without intimate
knowledge of the system.

One trick mentioned here recently is to use fprintf() to print to
/dev/null (or an equivalent data sink) and check the result. This
gives you the length for a given set of arguments, not the maximum for
the format, but substituting INT_MIN for "%d" and so forth might give
you the answers you're looking for. One drawback is that this
performs output (at least virtually), so the performance might not be
acceptable.
 
J

Jack Klein

Two points: INT_MAX and INT_MIN could differ by more than one, so

No, they can't. Look at paragraph 2 of 6.2.6.2 in the current
standard. INT_MIN must equal either -INT_MAX or (-INT_MAX - 1).

If you believe there is something in the standard that permits
anything else, please post the reference. I might be wrong, but I
don't think so.
 
E

Eric Sosman

Matt said:
Is there a clean, portable way to determine the maximum value of
converted numerical fields with printf()-like functions? Doing this
at compile-time would be preferable.

For example, %i should never convert to a string that is longer than
the number of digits in INT_MAX, right?

A negative value will be preceded by a minus sign,
so printing INT_MIN will produce one more character than
printing INT_MAX.

Floating-point conversions yield character counts that
are (I think) impossible to compute at compile time without
"outside help."

Depending on your application, you may also need to
worry about modifiers, e.g. "%99i", "%.18f". "%*.*g" might
be worst of all ...

C99 provides snprintf() and vsnprintf(), which won't
produce the answer as a compile-time value but will keep you
out of trouble if a particular conversion would take more
space than you allotted.
 
M

Michael Mair

Keith said:
Michael Mair said:
C89: The draft I use states that a single conversion can produce a
maximum of at least 509 characters.
C99 (standard): This limit goes up to 4095 characters.

Right, but I don't think that's what he's looking for. A C99
implementation isn't required to limit printf output to 4095
characters, so you can't assume that

char buf[4096];
sprintf(buf, some_format, arg1, arg2, arg3);

won't overflow the buffer.

Yep. Nonetheless, I think these environmental limits provide a
lower bound for or at least give an impression of sensible buffer
sizes.
As it is, I would use the respective buffer size in conjunction
with some strategy for error handling, i.e. if the static buffer
is not enough and a large enough dynamic buffer cannot be allocated,
one can try splitting the format string and at least get out
the minimum maximum number of characters per conversion...
A function that would take a format string and return the maximum
possible length of the output it can generate would solve the problem.
If the format string contains "%s", of course, the result is limited
only by the possible length of a string. The limit for "%d" would
typically be 6 on a system with 16-bit int, 11 on a system with 32-bit
int. Floating-point formats are a bit more challenging. The limit
for "%p" is difficult or impossible to determine without intimate
knowledge of the system.

One trick mentioned here recently is to use fprintf() to print to
/dev/null (or an equivalent data sink) and check the result. This
gives you the length for a given set of arguments, not the maximum for
the format, but substituting INT_MIN for "%d" and so forth might give
you the answers you're looking for. One drawback is that this
performs output (at least virtually), so the performance might not be
acceptable.

Well, on systems with such a "data sink" you also may have snprintf()
in the library, which IMO is a more obvious candidate for a solution.
Of course, one always should wrap a potentially not portable "character
count" solution appropriately...


Cheers
Michael
 
G

glen herrmannsfeldt

Matt said:
Is there a clean, portable way to determine the maximum value of
converted numerical fields with printf()-like functions? Doing this
at compile-time would be preferable.
For example, %i should never convert to a string that is longer than
the number of digits in INT_MAX, right?

Well, a negative number might have one more character.

The %f conversion could generate very large strings on some machines,
such as some CRAY machines.
I'd like to create a structure that contains character
representations of numerical types (e.g., instead of storing 3421 as
an int, it would store the char array "3421"). I'd like to make
these fields a fixed-size static array, but obviously I don't want
to make them too small.

I would say that you should make them big enough for the values
you expect them to hold. You could write your own functions to
do arithmetic on such strings, which would remove the limitation
on their size.

-- glen
 
K

Keith Thompson

glen herrmannsfeldt said:
Well, a negative number might have one more character.

The %f conversion could generate very large strings on some machines,
such as some CRAY machines.

Actually, the largest floating-point ranges I've seen are on systems
with 128-bit IEEE floating-point, including ordinary x86 systems.
It's basically the size of the exponent that determines how big a
string the "%f" conversion can generate; such systems typically have
32, 64, and 128 bit floating-point types with 8, 11, and 15 bit
exponents.

Many of the more recent Cray systems use IEEE floating-point. On the
vector systems that use Cray floating point, they seem to support
64-bit and 128-bit formats, both with 13-bit exponents; the 128-bit
format therefore supports a narrower range (but slightly more
precision) than the 128-bit IEEE format.
 
E

Eric Sosman

Keith said:
Actually, the largest floating-point ranges I've seen are on systems
with 128-bit IEEE floating-point, including ordinary x86 systems.
It's basically the size of the exponent that determines how big a
string the "%f" conversion can generate; [...]

printf ("%32767f", 0.0);
 
B

Ben Pfaff

Keith Thompson said:
Actually, the largest floating-point ranges I've seen are on systems
with 128-bit IEEE floating-point, including ordinary x86 systems.

Ordinary x86 systems do not have 128-bit IEEE floating-point,
unless by that you mean 80-bit IEEE floating-point plus 48
padding bits.
 
B

Ben Pfaff

Eric Sosman said:
Keith said:
It's basically the size of the exponent that determines how big a
string the "%f" conversion can generate; [...]

printf ("%32767f", 0.0);

That's undefined behavior:

7.19.6.1 The fprintf function
[...]
Environmental limits
15 The number of characters that can be produced by any single conversion shall be at least
4095.
 
K

Keith Thompson

Ben Pfaff said:
Ordinary x86 systems do not have 128-bit IEEE floating-point,
unless by that you mean 80-bit IEEE floating-point plus 48
padding bits.

Ok, quite possibly; I haven't looked into it in great detail.
 
J

Joe Wright

Ben said:
Keith said:
It's basically the size of the exponent that determines how big a
string the "%f" conversion can generate; [...]

printf ("%32767f", 0.0);


That's undefined behavior:

7.19.6.1 The fprintf function
[...]
Environmental limits
15 The number of characters that can be produced by any single conversion shall be at least
4095.
It says 'at least', not 'at most'.
 
B

Ben Pfaff

Joe Wright said:
Ben said:
Eric Sosman said:
Keith Thompson wrote:

It's basically the size of the exponent that determines how big a
string the "%f" conversion can generate; [...]

printf ("%32767f", 0.0);
That's undefined behavior:
7.19.6.1 The fprintf function
[...]
Environmental limits
15 The number of characters that can be produced by any single conversion shall be at least
4095.
It says 'at least', not 'at most'.

You can't depend on support for any more than the minimum, and
thus the behavior is undefined in general.
 
J

Jens.Toerring

Jack Klein said:
On 31 May 2005 20:27:55 GMT, (e-mail address removed)-berlin.de wrote
in comp.lang.c:
No, they can't. Look at paragraph 2 of 6.2.6.2 in the current
standard. INT_MIN must equal either -INT_MAX or (-INT_MAX - 1).
If you believe there is something in the standard that permits
anything else, please post the reference. I might be wrong, but I
don't think so.

It looks as if the screws got tightened quite a bit in C99 relative
to C89 - while I don't doubt what you write for C99 I haven't been
able to find something in the C89 standard that would nail down the
values that tightly. But that's probably due to me not reading the
whole thing carefully enough.
Regards, Jens
 
K

Keith Thompson

Ben Pfaff said:
Joe Wright said:
Ben said:
Keith Thompson wrote:

It's basically the size of the exponent that determines how big a
string the "%f" conversion can generate; [...]

printf ("%32767f", 0.0);
That's undefined behavior:
7.19.6.1 The fprintf function
[...]
Environmental limits
15 The number of characters that can be produced by any single
conversion shall be at least 4095.
It says 'at least', not 'at most'.

You can't depend on support for any more than the minimum, and
thus the behavior is undefined in general.

I suppose it's undefined behavior in the sense that the standard
doesn't guarantee that it will work. On the other hand, an
implementation could choose to guarantee a larger number of
characters, or it could state that there are no fixed limits, only
those imposed by resource constraints. (I think the latter is fairly
common.)

If I want to write a function that will take a printf-style format
string and return the maximum length of the resulting string (or an
error indicator if it contains something unbounded like "%s"), it
would be foolish to assume that the standard's limits will never be
exceeded.
 
C

CBFalconer

Keith said:
.... snip ...

If I want to write a function that will take a printf-style format
string and return the maximum length of the resulting string (or an
error indicator if it contains something unbounded like "%s"), it
would be foolish to assume that the standard's limits will never be
exceeded.

IMNSHO no output function should show invalid significant digits
after a decimal point. It should round the last digit as
appropriate, and output blanks from there on. For digits before a
decimal point zeroes can be used, with the same fundamental rule.
 
K

Keith Thompson

CBFalconer said:
IMNSHO no output function should show invalid significant digits
after a decimal point. It should round the last digit as
appropriate, and output blanks from there on. For digits before a
decimal point zeroes can be used, with the same fundamental rule.

Was that intended to be relevant to the paragraph you quoted?
 

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
474,164
Messages
2,570,898
Members
47,439
Latest member
shasuze

Latest Threads

Top