xref: /openbsd-src/lib/libc/stdio/printf.3 (revision fb8aa7497fded39583f40e800732f9c046411717)
1.\"	$OpenBSD: printf.3,v 1.75 2016/06/06 17:23:28 millert Exp $
2.\"
3.\" Copyright (c) 1990, 1991, 1993
4.\"	The Regents of the University of California.  All rights reserved.
5.\"
6.\" This code is derived from software contributed to Berkeley by
7.\" Chris Torek and the American National Standards Committee X3,
8.\" on Information Processing Systems.
9.\"
10.\" Redistribution and use in source and binary forms, with or without
11.\" modification, are permitted provided that the following conditions
12.\" are met:
13.\" 1. Redistributions of source code must retain the above copyright
14.\"    notice, this list of conditions and the following disclaimer.
15.\" 2. Redistributions in binary form must reproduce the above copyright
16.\"    notice, this list of conditions and the following disclaimer in the
17.\"    documentation and/or other materials provided with the distribution.
18.\" 3. Neither the name of the University nor the names of its contributors
19.\"    may be used to endorse or promote products derived from this software
20.\"    without specific prior written permission.
21.\"
22.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
23.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
24.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
25.\" ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
26.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
27.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
28.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
29.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
30.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
31.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
32.\" SUCH DAMAGE.
33.\"
34.\"     @(#)printf.3	8.1 (Berkeley) 6/4/93
35.\"
36.Dd $Mdocdate: June 6 2016 $
37.Dt PRINTF 3
38.Os
39.Sh NAME
40.Nm printf ,
41.Nm fprintf ,
42.Nm sprintf ,
43.Nm snprintf ,
44.Nm asprintf ,
45.Nm dprintf ,
46.Nm vprintf ,
47.Nm vfprintf ,
48.Nm vsprintf ,
49.Nm vsnprintf ,
50.Nm vasprintf ,
51.Nm vdprintf
52.Nd formatted output conversion
53.Sh SYNOPSIS
54.In stdio.h
55.Ft int
56.Fn printf "const char *format" ...
57.Ft int
58.Fn fprintf "FILE *stream" "const char *format" ...
59.Ft int
60.Fn sprintf "char *str" "const char *format" ...
61.Ft int
62.Fn snprintf "char *str" "size_t size" "const char *format" ...
63.Ft int
64.Fn asprintf "char **ret" "const char *format" ...
65.Ft int
66.Fn dprintf "int fd" "const char * restrict format" ...
67.In stdarg.h
68.In stdio.h
69.Ft int
70.Fn vprintf "const char *format" "va_list ap"
71.Ft int
72.Fn vfprintf "FILE *stream" "const char *format" "va_list ap"
73.Ft int
74.Fn vsprintf "char *str" "const char *format" "va_list ap"
75.Ft int
76.Fn vsnprintf "char *str" "size_t size" "const char *format" "va_list ap"
77.Ft int
78.Fn vasprintf "char **ret" "const char *format" "va_list ap"
79.Ft int
80.Fn vdprintf "int fd" "const char * restrict format" "va_list ap"
81.Sh DESCRIPTION
82The
83.Fn printf
84family of functions produce output according to the given
85.Fa format
86as described below.
87This format may contain
88.Dq conversion specifiers ;
89the results of such conversions, if any, depend on the arguments
90following the
91.Fa format
92string.
93.Pp
94The
95.Fn printf
96and
97.Fn vprintf
98functions write output to the standard output stream,
99.Em stdout ;
100.Fn fprintf
101and
102.Fn vfprintf
103write output to the supplied stream pointer
104.Fa stream ;
105.Fn dprintf
106and
107.Fn vdprintf
108write output to the given file descriptor;
109.Fn sprintf ,
110.Fn snprintf ,
111.Fn vsprintf ,
112and
113.Fn vsnprintf
114write to the character string
115.Fa str ;
116.Fn asprintf
117and
118.Fn vasprintf
119write to a dynamically allocated string that is stored in
120.Fa ret .
121.Pp
122These functions write the output under the control of a
123.Fa format
124string that specifies how subsequent arguments
125(or arguments accessed via the variable-length argument facilities of
126.Xr stdarg 3 )
127are converted for output.
128.Pp
129.Fn snprintf
130and
131.Fn vsnprintf
132will write at most
133.Fa size Ns \-1
134of the characters printed into the output string
135(the
136.Fa size Ns 'th
137character then gets the terminating
138.Ql \e0 ) ;
139if the return value is greater than or equal to the
140.Fa size
141argument, the string was too short
142and some of the printed characters were discarded.
143If
144.Fa size
145is zero,
146.Fa str
147may be a null pointer and no characters will be written;
148the number of bytes that would have been written excluding the terminating
149.Ql \e0
150byte, or \-1 on error, will be returned.
151.Pp
152.Fn sprintf
153and
154.Fn vsprintf
155effectively assume an infinite
156.Fa size .
157.Pp
158The format string is composed of zero or more directives:
159ordinary
160.\" multibyte
161characters (not
162.Cm % ) ,
163which are copied unchanged to the output stream,
164and conversion specifications, each of which results
165in fetching zero or more subsequent arguments.
166Each conversion specification is introduced by the character
167.Cm % .
168The arguments must correspond properly (after type promotion)
169with the conversion specifier.
170After the
171.Cm % ,
172the following appear in sequence:
173.Bl -bullet
174.It
175An optional field, consisting of a decimal digit string followed by a
176.Cm $
177specifying the next argument to access.
178If this field is not provided, the argument following the last
179argument accessed will be used.
180Arguments are numbered starting at
181.Cm 1 .
182.It
183Zero or more of the following flags:
184.Bl -hyphen
185.It
186A hash
187.Sq Cm #
188character
189specifying that the value should be converted to an
190.Dq alternate form .
191For
192.Cm o
193conversions, the precision of the number is increased to force the first
194character of the output string to a zero (except if a zero value is printed
195with an explicit precision of zero).
196For
197.Cm x
198and
199.Cm X
200conversions, a non-zero result has the string
201.Ql 0x
202(or
203.Ql 0X
204for
205.Cm X
206conversions) prepended to it.
207For
208.Cm a ,
209.Cm A ,
210.Cm e ,
211.Cm E ,
212.Cm f ,
213.Cm F ,
214.Cm g ,
215and
216.Cm G
217conversions, the result will always contain a decimal point, even if no
218digits follow it (normally, a decimal point appears in the results of
219those conversions only if a digit follows).
220For
221.Cm g
222and
223.Cm G
224conversions, trailing zeros are not removed from the result as they
225would otherwise be.
226For all other formats, behaviour is undefined.
227.It
228A zero
229.Sq Cm \&0
230character specifying zero padding.
231For all conversions except
232.Cm n ,
233the converted value is padded on the left with zeros rather than blanks.
234If a precision is given with a numeric conversion
235.Pf ( Cm d ,
236.Cm i ,
237.Cm o ,
238.Cm u ,
239.Cm x ,
240and
241.Cm X ) ,
242the
243.Sq Cm \&0
244flag is ignored.
245.It
246A negative field width flag
247.Sq Cm \-
248indicates the converted value is to be left adjusted on the field boundary.
249Except for
250.Cm n
251conversions, the converted value is padded on the right with blanks,
252rather than on the left with blanks or zeros.
253A
254.Sq Cm \-
255overrides a
256.Sq Cm \&0
257if both are given.
258.It
259A space, specifying that a blank should be left before a positive number
260produced by a signed conversion
261.Pf ( Cm d ,
262.Cm a ,
263.Cm A ,
264.Cm e ,
265.Cm E ,
266.Cm f ,
267.Cm F ,
268.Cm g ,
269.Cm G ,
270or
271.Cm i ) .
272.It
273A
274.Sq Cm +
275character specifying that a sign always be placed before a
276number produced by a signed conversion.
277A
278.Sq Cm +
279overrides a space if both are used.
280.El
281.It
282An optional decimal digit string specifying a minimum field width.
283If the converted value has fewer characters than the field width, it will
284be padded with spaces on the left (or right, if the left-adjustment
285flag has been given) to fill out
286the field width.
287.It
288An optional precision, in the form of a period
289.Sq Cm \&.
290followed by an
291optional digit string.
292If the digit string is omitted, the precision is taken as zero.
293This gives the minimum number of digits to appear for
294.Cm d ,
295.Cm i ,
296.Cm o ,
297.Cm u ,
298.Cm x ,
299and
300.Cm X
301conversions, the number of digits to appear after the decimal-point for
302.Cm a ,
303.Cm A ,
304.Cm e ,
305.Cm E ,
306.Cm f ,
307and
308.Cm F
309conversions, the maximum number of significant digits for
310.Cm g
311and
312.Cm G
313conversions, or the maximum number of characters to be printed from a
314string for
315.Cm s
316conversions.
317.It
318An optional length modifier, that specifies the size of the argument.
319The following length modifiers are valid for the
320.Cm d , i , n ,
321.Cm o , u , x ,
322or
323.Cm X
324conversion:
325.Bl -column "(deprecated)" "signed char" "unsigned long long" "long long *"
326.It Sy Modifier Ta Sy "d, i" Ta Sy "o, u, x, X" Ta Sy n
327.It hh Ta "signed char" Ta "unsigned char" Ta "signed char *"
328.It h Ta short Ta "unsigned short" Ta "short *"
329.It "l (ell)" Ta long Ta "unsigned long" Ta "long *"
330.It "ll (ell ell)" Ta "long long" Ta "unsigned long long" Ta "long long *"
331.It j Ta intmax_t Ta uintmax_t Ta "intmax_t *"
332.It t Ta ptrdiff_t Ta (see note) Ta "ptrdiff_t *"
333.It z Ta "(see note)" Ta size_t Ta "(see note)"
334.It "q (deprecated)" Ta quad_t Ta u_quad_t Ta "quad_t *"
335.El
336.Pp
337Note:
338the
339.Cm t
340modifier, when applied to an
341.Cm o , u , x ,
342or
343.Cm X
344conversion, indicates that the argument is of an unsigned type
345equivalent in size to a
346.Vt ptrdiff_t .
347The
348.Cm z
349modifier, when applied to a
350.Cm d
351or
352.Cm i
353conversion, indicates that the argument is of a signed type equivalent in
354size to a
355.Vt size_t .
356Similarly, when applied to an
357.Cm n
358conversion, it indicates that the argument is a pointer to a signed type
359equivalent in size to a
360.Vt size_t .
361.Pp
362The following length modifier is valid for the
363.Cm a ,
364.Cm A ,
365.Cm e ,
366.Cm E ,
367.Cm f ,
368.Cm F ,
369.Cm g ,
370or
371.Cm G
372conversion:
373.Bl -column "Modifier" "e, E, f, F, g, G"
374.It Sy Modifier Ta Sy "e, E, f, F, g, G"
375.It "l (ell)" Ta double (ignored: same behavior as without it)
376.It L Ta "long double"
377.El
378.Pp
379The following length modifier is valid for the
380.Cm c
381or
382.Cm s
383conversion:
384.Bl -column "Modifier" "wint_t" "wchar_t *"
385.It Sy Modifier Ta Sy c Ta Sy s
386.It "l (ell)" Ta wint_t Ta "wchar_t *"
387.El
388.It
389A character that specifies the type of conversion to be applied.
390.El
391.Pp
392A field width or precision, or both, may be indicated by
393an asterisk
394.Ql *
395or an asterisk followed by one or more decimal digits and a
396.Ql $
397instead of a
398digit string.
399In this case, an
400.Li int
401argument supplies the field width or precision.
402A negative field width is treated as a left adjustment flag followed by a
403positive field width; a negative precision is treated as though it were
404missing.
405If a single format directive mixes positional (nn$) and
406non-positional arguments, the results are undefined.
407.Pp
408The conversion specifiers and their meanings are:
409.Bl -tag -width "diouxX"
410.It Cm diouxX
411The
412.Li int
413(or appropriate variant) argument is converted to signed decimal
414.Pf ( Cm d
415and
416.Cm i ) ,
417unsigned octal
418.Pq Cm o ,
419unsigned decimal
420.Pq Cm u ,
421or unsigned hexadecimal
422.Pf ( Cm x
423and
424.Cm X )
425notation.
426The letters
427.Cm abcdef
428are used for
429.Cm x
430conversions; the letters
431.Cm ABCDEF
432are used for
433.Cm X
434conversions.
435The precision, if any, gives the minimum number of digits that must
436appear; if the converted value requires fewer digits, it is padded on
437the left with zeros.
438.It Cm DOU
439The
440.Li long int
441argument is converted to signed decimal, unsigned octal, or unsigned
442decimal, as if the format had been
443.Cm ld ,
444.Cm lo ,
445or
446.Cm lu
447respectively.
448These conversion characters are deprecated, and will eventually disappear.
449.It Cm eE
450The
451.Li double
452argument is rounded and converted in the style
453.Sm off
454.Pf [\-]d Cm \&. No ddd Cm e No \(+-dd
455.Sm on
456where there is one digit before the
457decimal-point character
458and the number of digits after it is equal to the precision;
459if the precision is missing,
460it is taken as 6; if the precision is
461zero, no decimal-point character appears.
462An
463.Cm E
464conversion uses the letter
465.Cm E
466(rather than
467.Cm e )
468to introduce the exponent.
469The exponent always contains at least two digits; if the value is zero,
470the exponent is 00.
471.Pp
472If the argument is infinity, it will be converted to [-]inf
473.Pq Cm e
474or [-]INF
475.Pq Cm E ,
476respectively.
477If the argument is not-a-number (NaN), it will be converted to
478[-]nan
479.Pq Cm e
480or [-]NAN
481.Pq Cm E ,
482respectively.
483.It Cm fF
484The
485.Li double
486argument is rounded and converted to decimal notation in the style
487.Sm off
488.Pf [-]ddd Cm \&. No ddd ,
489.Sm on
490where the number of digits after the decimal-point character
491is equal to the precision specification.
492If the precision is missing, it is taken as 6; if the precision is
493explicitly zero, no decimal-point character appears.
494If a decimal point appears, at least one digit appears before it.
495.Pp
496If the argument is infinity, it will be converted to [-]inf
497.Pq Cm f
498or [-]INF
499.Pq Cm F ,
500respectively.
501If the argument is not-a-number (NaN), it will be converted to
502[-]nan
503.Pq Cm f
504or [-]NAN
505.Pq Cm F ,
506respectively.
507.It Cm gG
508The
509.Li double
510argument is converted in style
511.Cm f
512or
513.Cm e
514(or
515.Cm E
516for
517.Cm G
518conversions).
519The precision specifies the number of significant digits.
520If the precision is missing, 6 digits are given; if the precision is zero,
521it is treated as 1.
522Style
523.Cm e
524is used if the exponent from its conversion is less than -4 or greater than
525or equal to the precision.
526Trailing zeros are removed from the fractional part of the result; a
527decimal point appears only if it is followed by at least one digit.
528.Pp
529If the argument is infinity, it will be converted to [-]inf
530.Pq Cm g
531or [-]INF
532.Pq Cm G ,
533respectively.
534If the argument is not-a-number (NaN), it will be converted to
535[-]nan
536.Pq Cm g
537or [-]NAN
538.Pq Cm G ,
539respectively.
540.It Cm aA
541The
542.Li double
543argument is rounded and converted to hexadecimal notation in the style
544.Sm off
545.Pf [\-]0xh Cm \&. No hhh Cm p No [\(+-]d
546.Sm on
547where the number of digits after the hexadecimal-point character
548is equal to the precision specification.
549If the precision is missing, it is taken as enough to represent
550the floating-point number exactly, and no rounding occurs.
551If the precision is zero, no hexadecimal-point character appears.
552The
553.Cm p
554is a literal character
555.Ql p ,
556and the exponent consists of a positive or negative sign
557followed by a decimal number representing an exponent of 2.
558The
559.Cm A
560conversion uses the prefix
561.Dq Li 0X
562(rather than
563.Dq Li 0x ) ,
564the letters
565.Dq Li ABCDEF
566(rather than
567.Dq Li abcdef )
568to represent the hex digits, and the letter
569.Ql P
570(rather than
571.Ql p )
572to separate the mantissa and exponent.
573.Pp
574Note that there may be multiple valid ways to represent floating-point
575numbers in this hexadecimal format.
576For example,
577.Li 0x3.24p+0 , 0x6.48p-1
578and
579.Li 0xc.9p-2
580are all equivalent.
581The format chosen depends on the internal representation of the
582number, but the implementation guarantees that the length of the
583mantissa will be minimized.
584Zeroes are always represented with a mantissa of 0 (preceded by a
585.Ql -
586if appropriate) and an exponent of
587.Li +0 .
588.Pp
589If the argument is infinity, it will be converted to [-]inf
590.Pq Cm a
591or [-]INF
592.Pq Cm A ,
593respectively.
594If the argument is not-a-number (NaN), it will be converted to
595[-]nan
596.Pq Cm a
597or [-]NAN
598.Pq Cm A ,
599respectively.
600.It Cm c
601The
602.Li int
603argument is converted to an
604.Li unsigned char ,
605and the resulting character is written.
606.It Cm s
607The
608.Li char *
609argument is expected to be a pointer to an array of character type (pointer
610to a string).
611Characters from the array are written up to (but not including)
612a terminating NUL character;
613if a precision is specified, no more than the number specified are
614written.
615If a precision is given, no NUL character need be present;
616if the precision is not specified, or is greater than the size
617of the array, the array must contain a terminating NUL character.
618.It Cm p
619The
620.Li void *
621pointer argument is printed in hexadecimal (as if by
622.Ql %#x
623or
624.Ql %#lx ) .
625.It Cm n
626The number of characters written so far is stored into the
627integer indicated by the
628.Li int *
629(or variant) pointer argument.
630No argument is converted.
631.It Cm %
632A
633.Ql %
634is written.
635No argument is converted.
636The complete conversion specification is
637.Ql %% .
638.El
639.Pp
640In no case does a non-existent or small field width cause truncation of
641a field; if the result of a conversion is wider than the field width, the
642field is expanded to contain the conversion result.
643.Sh RETURN VALUES
644For all these functions if an output or encoding error occurs, a value
645less than 0 is returned.
646.Pp
647The
648.Fn printf ,
649.Fn fprintf ,
650.Fn sprintf ,
651.Fn vprintf ,
652.Fn vfprintf ,
653.Fn vsprintf ,
654.Fn asprintf ,
655and
656.Fn vasprintf
657functions
658return the number of characters printed
659(not including the trailing
660.Ql \e0
661used to end output to strings).
662.Pp
663The
664.Fn snprintf
665and
666.Fn vsnprintf
667functions return the number of characters that would have
668been output if the
669.Fa size
670were unlimited
671.Po
672again, not including the final
673.Ql \e0 .
674.Pc .
675.Pp
676The
677.Fn asprintf
678and
679.Fn vasprintf
680functions return the number of characters that were output
681to the newly allocated string
682(excluding the final
683.Ql \e0 ) .
684A pointer to the newly allocated string is returned in
685.Fa ret ;
686it should be passed to
687.Xr free 3
688to release the allocated storage
689when it is no longer needed.
690If sufficient space cannot be allocated, these functions
691will return \-1.
692The value of
693.Fa ret
694in this situation is implementation-dependent
695(on
696.Ox ,
697.Fa ret
698will be set to the null pointer, but this behavior should not be relied upon).
699.Sh EXAMPLES
700To print a date and time in the form `Sunday, July 3, 10:02',
701where
702.Va weekday
703and
704.Va month
705are pointers to strings:
706.Bd -literal -offset indent
707#include <stdio.h>
708
709fprintf(stdout, "%s, %s %d, %.2d:%.2d\en",
710    weekday, month, day, hour, min);
711.Ed
712.Pp
713To print \*(Pi
714to five decimal places:
715.Bd -literal -offset indent
716#include <math.h>
717#include <stdio.h>
718
719fprintf(stdout, "pi = %.5f\en", 4 * atan(1.0));
720.Ed
721.Pp
722To allocate a 128-byte string and print into it:
723.Bd -literal -offset indent
724#include <stdarg.h>
725#include <stdio.h>
726#include <stdlib.h>
727
728char *
729newfmt(const char *fmt, ...)
730{
731	char *p;
732	va_list ap;
733
734	if ((p = malloc(128)) == NULL)
735		return (NULL);
736	va_start(ap, fmt);
737	(void) vsnprintf(p, 128, fmt, ap);
738	va_end(ap);
739	return (p);
740}
741.Ed
742.Sh ERRORS
743In addition to the errors documented for the
744.Xr write 2
745system call, the
746.Fn printf
747family of functions may fail if:
748.Bl -tag -width Er
749.It Bq Er EILSEQ
750An invalid wide character code was encountered.
751.It Bq Er ENOMEM
752Insufficient storage space is available.
753.It Bq Er EOVERFLOW
754The return value would be too large to be represented by an
755.Vt int .
756.El
757.Sh SEE ALSO
758.Xr printf 1 ,
759.Xr scanf 3
760.Sh STANDARDS
761The
762.Fn fprintf ,
763.Fn printf ,
764.Fn snprintf ,
765.Fn sprintf ,
766.Fn vfprintf ,
767.Fn vprintf ,
768.Fn vsnprintf ,
769and
770.Fn vsprintf
771functions conform to
772.St -isoC-99 .
773The
774.Fn dprintf
775and
776.Fn vdprintf
777functions conform to
778.St -p1003.1-2008 .
779.Sh HISTORY
780The predecessors
781.Fn ftoa
782and
783.Fn itoa
784first appeared in
785.At v1 .
786The function
787.Fn printf
788first appeared in
789.At v2 ,
790and
791.Fn fprintf
792and
793.Fn sprintf
794in
795.At v7 .
796.Pp
797The functions
798.Fn snprintf
799and
800.Fn vsnprintf
801first appeared in
802.Bx 4.4 .
803.Pp
804The functions
805.Fn asprintf
806and
807.Fn vasprintf
808first appeared in the GNU C library.
809This implementation first appeared in
810.Ox 2.3 .
811.Pp
812The functions
813.Fn dprintf
814and
815.Fn vdprintf
816first appeared in
817.Ox 5.3 .
818.Sh CAVEATS
819The conversion formats
820.Cm \&%D ,
821.Cm \&%O ,
822and
823.Cm \&%U
824are not standard and
825are provided only for backward compatibility.
826The effect of padding the
827.Cm %p
828format with zeros (either by the
829.Sq Cm 0
830flag or by specifying a precision), and the benign effect (i.e., none)
831of the
832.Sq Cm #
833flag on
834.Cm %n
835and
836.Cm %p
837conversions, as well as other
838nonsensical combinations such as
839.Cm %Ld ,
840are not standard; such combinations
841should be avoided.
842.Pp
843Because
844.Fn sprintf
845and
846.Fn vsprintf
847assume an infinitely long string,
848callers must be careful not to overflow the actual space;
849this is often impossible to assure.
850For safety, programmers should use the
851.Fn snprintf
852and
853.Fn asprintf
854family of interfaces instead.
855Unfortunately, the
856.Fn asprintf
857interface is not available on all systems as it is not part of
858.St -isoC-99 .
859.Pp
860It is important never to pass a string with user-supplied data as a
861format without using
862.Ql %s .
863An attacker can put format specifiers in the string to mangle the stack,
864leading to a possible security hole.
865This holds true even if the string has been built
866.Dq by hand
867using a function like
868.Fn snprintf ,
869as the resulting string may still contain user-supplied conversion specifiers
870for later interpolation by
871.Fn printf .
872.Pp
873Be sure to use the proper secure idiom:
874.Bd -literal -offset indent
875int ret = snprintf(buffer, sizeof(buffer), "%s", string);
876if (ret == -1 || ret >= sizeof(buffer))
877	goto toolong;
878.Ed
879.Pp
880There is no way for
881.Fn printf
882to know the size of each argument passed.
883If positional arguments are used, care must be taken to ensure that all
884parameters, up to the
885last positionally specified parameter, are used in the format string.
886This allows for the format string to be parsed for this information.
887Failure to do this will mean the code is non-portable and liable to fail.
888