Node:Formatting Numbers, Previous:Locale Information, Up:Locales
We have seen that the structure returned by localeconv
as well as
the values given to nl_langinfo
allow you to retrieve the various
pieces of locale-specific information to format numbers and monetary
amounts. We have also seen that the underlying rules are quite complex.
Therefore the X/Open standards introduce a function which uses such
locale information, making it easier for the user to format
numbers according to these rules.
ssize_t strfmon (char *s, size_t maxsize, const char *format, ...) | Function |
The strfmon function is similar to the strftime function
in that it takes a buffer, its size, a format string,
and values to write into the buffer as text in a form specified
by the format string. Like strftime , the function
also returns the number of bytes written into the buffer.
There are two differences: strfmon can take more than one
argument, and, of course, the format specification is different. Like
strftime , the format string consists of normal text, which is
output as is, and format specifiers, which are indicated by a % .
Immediately after the % , you can optionally specify various flags
and formatting information before the main formatting character, in a
similar way to printf :
- flag determines the side at which such padding occurs. If
present, the spaces are added at the right making the output
left-justified, and vice versa.
So far the format looks familiar, being similar to the printf and
strftime formats. However, the next two optional fields
introduce something new. The first one is a # character followed
by a decimal digit string. The value of the digit string specifies the
number of digit positions to the left of the decimal point (or
equivalent). This does not include the grouping character when
the ^ flag is not given. If the space needed to print the number
does not fill the whole width, the field is padded at the left side with
the fill character, which can be selected using the = flag and by
default is a space. For example, if the field width is selected as 6
and the number is 123, the fill character is * the result
will be ***123 .
The second optional field starts with a . (period) and consists
of another decimal digit string. Its value describes the number of
characters printed after the decimal point. The default is selected
from the current locale (frac_digits , int_frac_digits , see
see General Numeric). If the exact representation needs more digits
than given by the field width, the displayed value is rounded. If the
number of fractional digits is selected to be zero, no decimal point is
printed.
As a GNU extension, the strfmon implementation in the GNU libc
allows an optional L next as a format modifier. If this modifier
is given, the argument is expected to be a long double instead of
a double value.
Finally, the last component is a format specifier. There are three
specifiers defined:
printf , the function reads the format string
from left to right and uses the values passed to the function following
the format string. The values are expected to be either of type
double or long double , depending on the presence of the
modifier L . The result is stored in the buffer pointed to by
s. At most maxsize characters are stored.
The return value of the function is the number of characters stored in
s, including the terminating NULL byte. If the number of
characters stored would exceed maxsize, the function returns
-1 and the content of the buffer s is unspecified. In this
case errno is set to E2BIG .
|
en_US
). The simplest
form of the format is this:
strfmon (buf, 100, "@%n@%n@%n@", 123.45, -567.89, 12345.678);The output produced is
"@$123.45@-$567.89@$12,345.68@"We can notice several things here. First, the widths of the output numbers are different. We have not specified a width in the format string, and so this is no wonder. Second, the third number is printed using thousands separators. The thousands separator for the
en_US
locale is a comma. The number is also rounded.
.678 is rounded to .68 since the format does not specify a
precision and the default value in the locale is 2. Finally,
note that the national currency symbol is printed since %n
was
used, not i
. The next example shows how we can align the output.
strfmon (buf, 100, "@%=*11n@%=*11n@%=*11n@", 123.45, -567.89, 12345.678);The output this time is:
"@ $123.45@ -$567.89@ $12,345.68@"Two things stand out. Firstly, all fields have the same width (eleven characters) since this is the width given in the format and since no number required more characters to be printed. The second important point is that the fill character is not used. This is correct since the white space was not used to achieve a precision given by a
#
modifier, but instead to fill to the given width. The difference
becomes obvious if we now add a width specification.
strfmon (buf, 100, "@%=*11#5n@%=*11#5n@%=*11#5n@", 123.45, -567.89, 12345.678);The output is
"@ $***123.45@-$***567.89@ $12,456.68@"Here we can see that all the currency symbols are now aligned, and that the space between the currency sign and the number is filled with the selected fill character. Note that although the width is selected to be 5 and 123.45 has three digits left of the decimal point, the space is filled with three asterisks. This is correct since, as explained above, the width does not include the positions used to store thousands separators. One last example should explain the remaining functionality.
strfmon (buf, 100, "@%=0(16#5.3i@%=0(16#5.3i@%=0(16#5.3i@", 123.45, -567.89, 12345.678);This rather complex format string produces the following output:
"@ USD 000123,450 @(USD 000567.890)@ USD 12,345.678 @"The most noticeable change is the alternative way of representing negative numbers. In financial circles this is often done using parentheses, and this is what the
(
flag selected. The fill
character is now 0
. Note that this 0
character is not
regarded as a numeric zero, and therefore the first and second numbers
are not printed using a thousands separator. Since we used the format
specifier i
instead of n
, the international form of the
currency symbol is used. This is a four letter string, in this case
"USD "
. The last point is that since the precision right of the
decimal point is selected to be three, the first and second numbers are
printed with an extra zero at the end and the third number is printed
without rounding.