Наконец, точность справа состоит из символа '.
' и строки десятичных цифр. Она указывает, с каким числом значащих цифр округлить значение до форматирования. По умолчанию используются поля frac_digits
и int_frac_digits
в struct lconv
. Если это значение равно 0, десятичная точка не выводится.
strfmon()
возвращает число символов, помещенных в буфер, не включая завершающий нулевой байт. Если недостаточно места, функция возвращает -1 и устанавливает errno
в E2BIG
.
Помимо strfmon()
, POSIX (но '
— для форматов printf()
%i
, %d
, %u
, %f
, %F
, %g
и %G
. В локалях, имеющих разделитель тысяч, этот флаг добавляет и его. Следующая простая программа, ch13-quoteflag.c
, демонстрирует вывод:
/* ch13-quoteflag.c --- демонстрация флага кавычки printf */
#include
#include
int main(void) {
setlocale(LC_ALL, ""); /* Это нужно, иначе не будет работать */
printf("%'d\n", 1234567);
return 0;
}
Вот что происходит для двух различных локалей: в одной есть разделитель тысяч, в другой нет:
$ LC_ALL=C ch13-quoteflag /* Обычное окружение без разделителя */
1234567
$ LC_ALL=en_US ch13-quoteflag /* Локаль с разделителем (англ.) */
1,234,567
На время написания лишь GNU/Linux и Solaris поддерживают флаг '
. Дважды проверьте справочную страницу
13.2.6. Пример: форматирование числовых значений в gawk
gawk
реализует свои собственные версии функций printf()
и sprintf()
. Для полного использования локали gawk
должен поддерживать флаг '
, как в С. Следующий фрагмент из файла builtin.c
в gawk
3.1.4 показывает, как gawk
использует struct lconv
для числового форматирования:
1 case 'd':
2 case 'i':
3 ...
4 tmpval = force_number(arg);
5
6 ...
7 uval = (uintmax_t)tmpval;
8 ...
9 ii = jj = 0;
10 do {
11 *--cp = (char)('0' + uval % 10);
12 #ifdef HAVE_LOCALE_H
13 if (quote_flag && loc.grouping[ii] && ++jj == loc.grouping[ii]) {
14 *--cp = loc.thousands_sep[0]; /* XXX - предположение, что это один символ */
15 if (loc.grouping[ii+1] == 0)
16 jj = 0; /* продолжить использовать текущий val в loc.grouping [ii] */
17 else if (loc.grouping[ii+1] == CHAR_MAX)
18 quote_flag = FALSE;
19 else {
20 ii++;
21 jj = 0;
22 }
23 }
24 #endif
25 uval /= 10;
26 } while (uval > 0);
(Номера строк даны относительно начала фрагмента.) Некоторые части кода, не имеющие отношения к обсуждению, были опущены, чтобы облегчить фокусировку на важных частях.
Переменная loc
, используемая в строках 13–17, представляет struct lconv
. Она инициализируется в main()
. Здесь для нас интерес представляет loc.thousands_sep
, который является символом разделителя тысяч, и loc.grouping
, который является массивом, описывающим число цифр между разделителями. Нулевой элемент означает «использовать для всех последующих цифр значение предыдущего элемента», а значение CHAR_MAX
означает «прекратить вставку разделителей тысяч».
С таким введением, давайте посмотрим на код. Строка 7 устанавливает uval
, которая является беззнаковой версией форматируемого значения. ii
и jj
отслеживают положение в loc.grouping
и число цифр в текущей группе, которые были преобразованы, соответственно[142]. quote_flag
равен true, когда в спецификации преобразования был отмечен символ '
.
Цикл do-while
генерирует символы цифр в обратном порядке, заполняя буфер с конца к началу. Каждая цифра создается в строке 11. Затем строка 25 делится на 10 путем смещения значения вправо на одну десятичную цифру.
Нас интересуют строки 12–24. Эта работа осуществляется только на системе, поддерживающей локали, на что указывает наличие заголовочного файла
. Именованная константа HAVE_LOCALE
в такой системе будет равна true[143].