Программирование ARM IAR EWB ARM: форматированный вывод printf библиотеки DLIB Thu, March 28 2024  

Поделиться

Нашли опечатку?

Пожалуйста, сообщите об этом - просто выделите ошибочное слово или фразу и нажмите Shift Enter.

IAR EWB ARM: форматированный вывод printf библиотеки DLIB Печать
Добавил(а) microsin   

Как и многие системы программирования на языке C, IAR Embedded Workbench for ARM имеет так называемые средства форматированного вывода (Formatted Output). Это упрощает текстовый вывод данных всевозможных типов в консоль экрана либо в строку с помощью функций fprintf, printf, sprintf, vfprintf, vprintf и vsprintf. Далее представлен перевод help IAR (Help -> Content... -> закладка Поиск -> введите в поле ввода formated output, нажмите Enter -> в появившемся списке разделов двойным щелчком кликните на Formatted Output DLIB).

По умолчанию в проекте IAR для вывода настроена библиотека DLIB. Некоторые функции этой библиотеки помогут Вам преобразовать значения данных (переменных, констант) из их внутреннего представления в текстовую последовательность, которая удобна для чтения человеком. Вы предоставляете строку формата (format string) как значение аргумента формата для каждой такой функции. Функции fprintf, printf, sprintf, vfprintf, vprintf и vsprintf (они определены в < stdio.h >) преобразуют внутреннее представление данных различных типов в последовательность данных типа char, и помогают Вам в составлении таких последовательностей. Для этих функций строка формата (format string) является строкой из многих байтов, которая начинается и заканчивается так называемым начальным состоянием смещения (initial shift state).

[Форматы печати (Print Formats)]

Строка формата имеет одинаковый синтаксис и для функций печати (типа pfrintf, sprintf и т. п.), для сканирующих функций форматированного ввода (scan functions, наподобие sscanf). Разбор синтаксиса строки показан на диаграмме.

format-string-syntax

Строка формата может включать в себя (а может и не включать, если выводится просто текст) один или более спецификаторов преобразования (conversion specifications), окруженных обычным текстом (literal text) и пробелами (white space). White space - это последовательность из одного или большего количества символов c, для которых результат вызова функции isspace(c) будет ненулевым. Обычно это символ ' ' с ASCII-кодом 0x20, причем символ для white space можно перезадать категории локали LC_CTYPE, см. файл < locale.h > и документацию к нему. Для функций печати (print functions) спецификаторами преобразования являются print conversion specifications, которые описаны далее.

Функция печати сканирует строку формата от начала до конца, чтобы определить, какие преобразования нужно выполнить. Каждая функция печати принимает произвольное количество аргументов, либо работает под непосредственным управлением аргумента типа va_list. Некоторые спецификации преобразования печати в строке формата используют следующий параметр в списке. Функция печати использует каждый свой последовательный аргумент не больше, чем один раз. Некоторые последние аргументы (если они не имеют соответствующего им спецификатора преобразования) могут остаться неиспользуемыми. Если аргументов недостаточно (то есть их выявлено меньше, чем имеется спецификаторов преобразования в строке формата), то компилятор выдаст соответствующее предупреждение (Warning[Pe224]: the format string requires additional arguments имя_модуля.c номер_строки).

Далее в описании приняты следующие соглашения о терминах:

- integer conversions (целочисленные преобразования) - это спецификаторы преобразования (conversion specifiers), которые оканчиваются на d, i, o, u, x, или X
- floating-point conversions (преобразования с плавающей точкой) - это спецификаторы преобразования, которые оканчиваются на e, E, f, g, or G

[Функции печати (Print Functions)]

Для функций печати (printf, sprintf и т. п.) простой текст или пробел в строке формата генерирует такой же текст, который соответствует строке формата. Спецификация преобразования печати (print conversion specification) обычно генерирует символы путем преобразования следующего значения аргумента в соответствующую последовательность текста. Вот формат print conversion specification:

print-conversion-specification

Жирным текстом на картинке показаны возможности, добавленные в стандарте C99.

За символом процента (%) в строке формата Вы можете указать ноль или большее количество флагов формата (format flags):

- для преобразования, выровненного по левому краю
+ для генерации знака "плюс" для значений со знаком (signed), которые положительные
space (пробел) для генерации пробела для значений со знаком (signed), которые не имеют в ни знака "плюс", ни знака "минус" (т. е. для положительных значений)
# для префиксного 0 преобразования o, для префикса 0x преобразования x, для префикса 0X преобразования X, или для генерации десятичной точки и чисел дробной части, которые в противном случае будут подавлены на преобразовании с плавающей точкой
0 для дополнения преобразования начальными нулями после любого знака или префикса, при отсутствии флага формата минус (-) или указанной точности

После любого формата флагов Вы можете указать ширину поля (field width), которое определяет минимальное количество символов для генерации при преобразовании. За исключением случая отмены флагом формата, поведение по умолчанию - слева дополнять пробелами короткое преобразование. Если Вы укажете звездочку (*), вместо десятичного значения в поле ширины, то функция печати принимает значение следующего аргумента (который должен быть целого типа, int) как поле ширины. Если аргумент имеет отрицательное значение, он предоставляет флаг формата "-" и величину поля ширины.

После любого поля ширины Вы можете указать точку (.), за которой идет точность (precision), которая указывает один из следующих вариантов:
- либо минимальное количество цифр для генерации целочисленного преобразования,
- либо количество цифр дробной части для генерации преобразований e, E или f,
- либо максимальное количество значимых цифр для преобразований g или G,
- либо максимальное количество символов для генерации C-строки (C string) преобразования s.

Вы можете указать * вместо десятичной цифры для точности, при этом функция печати принимает значение следующего аргумента (который должен быть целого типа, int) как поле точности. Если аргумент имеет отрицательное значение, то используется точность по умолчанию. Если Вы не указали * или десятичное число после точки, то точность будет ноль.

[Спецификаторы преобразования печати (Print Conversion Specifiers)]

После указания поля точности Вы можете указать один символ print conversion specifier, которому может предшествовать односимвольный или двухсимвольный квалификатор. Каждая комбинация определяет тип, который требуется для соответствующего преобразуемого аргумента (если он есть), и как библиотечные функции меняют значение аргумента перед его преобразованием в текстовую последовательность. Преобразования integer и floating-point также определяют базу для использования текстового представления. Если спецификатор преобразования требует точности p, и Вы не предоставили её в формате, спецификатор преобразования выбирает значение для умолчания для точности. В следующей таблице перечислены все заданные комбинации и их свойства.

Conversion Specifier
(спецификатор преобразования)
Тип аргумента Преобразуемое
значение
Основание по
умолчанию
Точность
(precision)
Примечание
%a double x (double)x 10 6 добавлено в стандарте C99
%La long double x (long double)x 10 6 добавлено в стандарте C99
%A double x (double)x 10 6 добавлено в стандарте C99
%LA double x (long double)x 10 6 добавлено в стандарте C99
%c int x (unsigned char)x
%lc wint_t x wchar_t a[2] = {x}
%d int x (int)x 10 1
%hd int x (short)x 10 1
%ld long x (long)x 10 1
%hhd int x (signed char)x 10 1 добавлено в стандарте C99
%jd intmax_t x (intmax_t)x 10 1 добавлено в стандарте C99
%lld long long x (long long)x 10 1 добавлено в стандарте C99
%td ptrdiff_t x (ptrdiff_t)x 10 1 добавлено в стандарте C99
%zd size_t x (ptrdiff_t)x 10 1 добавлено в стандарте C99
%e double x (double)x 10 6
%Le long double x (long double)x 10 6
%E double x (double)x 10 6
%LE long double x (long double)x 10 6
%f double x (double)x 10 6
LF long double x (long double)x 10 6
%F double x (double)x 10 6 добавлено в стандарте C99
%LF long double x (long double)x 10 6 добавлено в стандарте C99
%g double x (double)x 10 6
%Lg long double x (long double)x 10 6
%G double x (double)x 10 6
%LG long double x (long double)x 10 6
%i int x (int)x 10 1
%hi int x (short)x 10 1
%li long x (long)x 10 1
%hhi int x (signed char)x 10 1 добавлено в стандарте C99
%ji intmax_t x (intmax_t)x 10 1 добавлено в стандарте C99
%lli long long x (long long)x 10 1 добавлено в стандарте C99
%ti ptrdiff_t x (ptrdiff_t)x 10 1 добавлено в стандарте C99
%zi size_t x (ptrdiff_t)x 10 1 добавлено в стандарте C99
%n int *x
%hn short *x
%ln long *x
%hhn int *x добавлено в стандарте C99
%jn intmax_t *x добавлено в стандарте C99
%lln long long *x добавлено в стандарте C99
%tn ptrdiff_t *x добавлено в стандарте C99
%zn size_t *x добавлено в стандарте C99
%o int x (unsigned int)x 8 1
%ho int x (unsigned short)x 8 1
%lo long x (unsigned long)x 8 1
%hho int x (unsigned char)x 8 1 добавлено в стандарте C99
%jo intmax_t x (uintmax_t)x 8 1 добавлено в стандарте C99
%llo long long x (unsigned long long)x 8 1 добавлено в стандарте C99
%to ptrdiff_t x (size_t)x 8 1 добавлено в стандарте C99
%zo size_t x (size_t)x 8 1 добавлено в стандарте C99
%p void *x (void *)x
%s char x[] x[0]... large
%ls wchar_t x[] x[0]... large
%u int x (unsigned int)x 10 1
%hu int x (unsigned short)x 10 1
%lu long x (unsigned long)x 10 1
%hhu int x (unsigned char)x 8 1 добавлено в стандарте C99
%ju intmax_t x (uintmax_t)x 8 1 добавлено в стандарте C99
%llu long long x (unsigned long long)x 8 1 добавлено в стандарте C99
%tu ptrdiff_t x (size_t)x 8 1 добавлено в стандарте C99
%zu size_t x (size_t)x 8 1 добавлено в стандарте C99
%x int x (unsigned int)x 16 1
%hx int x (unsigned short)x 16 1
%lx long x (unsigned long)x 16 1
%hhx int x (unsigned char)x 8 1 добавлено в стандарте C99
%jx intmax_t x (uintmax_t)x 8 1 добавлено в стандарте C99
%llx long long x (unsigned long long)x 8 1 добавлено в стандарте C99
%tx ptrdiff_t x (size_t)x 8 1 добавлено в стандарте C99
%zx size_t x (size_t)x 8 1 добавлено в стандарте C99
%X int x (unsigned int)x 16 1
%hX int x (unsigned short)x 16 1
%lX long x (unsigned long)x 16 1
%hhX int x (unsigned char)x 8 1 добавлено в стандарте C99
%jX intmax_t x (uintmax_t)x 8 1 добавлено в стандарте C99
%llX long long x (unsigned long long)x 8 1 добавлено в стандарте C99
%tX ptrdiff_t x (size_t)x 8 1 добавлено в стандарте C99
%zX size_t x (size_t)x 8 1 добавлено в стандарте C99
%% нет '%'

Спецификаторы print conversion определяют также любое поведение, которое не сведено в эту таблицу. Для всех преобразований с плавающей точкой:

- Положительная бесконечность печатается как inf или INF (от слова infinity).
- Отрицательная бесконечность печатается как -inf или -INF.
- Не число (Not-a-number, NaN) печатается как nan или NAN.

Версии верхнего регистра (upper-case) печатаются только conversion specifier в верхнем регистре, такого как %E, но не как %Lg.

Далее в примерах символом p обозначается точность (precision). Примеры следуют каждым спецификаторам преобразования. Одиночное преобразование может сгенерировать до 509 символов.

Укажите %a или %A для генерации шестнадцатеричного дробного представления со знаком, с десятичной экспонентой степени двойки. Генерируемый текст получается вида ±0Xh.hhhP±dd, где ± либо плюс либо минус, символ X либо x (для преобразования %a), либо X (для преобразования %A), символ h шестнадцатеричная цифра, символ d десятичная цифра, шестнадцатеричная точка (.) является десятичной точкой для текущей локализации (current locale), и символ P будет либо p (для преобразования %a), либо P (для преобразования %A). Сгенерированный текст имеет одну целую цифру, которая будет 0 только для нулевого значения, шестнадцатеричная точка если имеются любые цифры дроби, или если Вы указали флаг формата # для большинства p цифр дробной части без завершающих нулей, и как минимум одну цифру экспоненты без лидирующих нулей. Результат будет округлен. Значение 0 имеет нулевую экспоненту. Примеры:

printf("%a", 30.0);                //печатает 0x1ep+1
printf("%.2A", 30.0);              //печатает 0X1.E0P+1

Укажите %c для генерации одного символа из преобразуемого значения.

printf("%c", 'a');                 //печатает a
printf("<%3c|%-3c>", 'a', 'b');    //печатает < a|b >

Укажите %d, %i, %o, %u, %x или %X для генерации возможного представления целого числа со знаком (signed integer). Варианты %d или %i указывают десятичное со знаком (signed decimal), %o беззнаковое восьмеричное (unsigned octal), %u беззнаковое десятичное (unsigned decimal), %x беззнаковое шестнадцатеричное (unsigned hexadecimal) с использованием символов 0-9 и a-f, %X unsigned hexadecimal с использованием символов 0-9 и A-F. Преобразование генерирует как минимум p цифр, полученных из преобразуемого значения. Если p ноль, то конвертируемая величина 0 не генерирует цифр.

printf("%d %o %x", 31, 31, 31);    //печатает 31 37 1f
printf("%hu", 0xffff);             //печатает 65535
printf("%#X %+d", 31, 31);         //печатает 0X1F +31

Укажите %e или %E для генерации представления десятичного дробного числа со знаком (signed decimal fractional) с десятичной экспонентой степени 10. Генерируемый текст получится вида ±d.dddE±dd, где ± знак либо плюса, либо минуса, d десятичная цифра, десятичная точка (.) это десятичная точка для текущего языка локали, E это или e (для преобразования %e) или E (для преобразования %E). Генерируемый текст имеет одну целую цифру, десятичную точку если p ненулевое или если Вы указали флаг формата #, p цифр дробной, и как минимум две цифры экспоненты. Результат округляется. Значение 0 имеет нулевую экспоненту.

printf("%e", 31.4);                //печатает 3.140000e+01
printf("%.2E", 31.4);              //печатает 3.14E+01

Укажите %f или %F для генерации представления десятичного дробного числа со знаком без экспоненты (signed decimal fractional, no exponent). Сгенерированный текст будет в форме ±d.ddd, где ± знак либо плюса, либо минуса, d десятичная цифра, и десятичной точкой (.) является десятичная точка для текущей языковой локали. Сгенерированный текст имеет как минимум одну целую цифру, десятичную точку, если p не ноль или если Вы указали флаг формата #, и p цифр дробной части. Результат округляется.

printf("%f", 31.4);                //печатает 31.400000
printf("%.0f %#.0f", 31.0, 31.0);  //печатает 31 31.

Укажите %g или %G для генерации представления дробного десятичного числа со знаком (signed decimal fractional), у которого есть или нет десятичная экспонента степени 10, если это подходит. Для преобразования %g генерируемый текст получается в той же форме, что и преобразование %e или %f. Для преобразования %G получается та же форма текста, что и для преобразования %E или %F. Точность p указывает количество генерируемых значащих цифр (если p нулевая, то она меняется на 1). Если преобразование %e приведет к экспоненте в диапазоне (-4, p), то вместо этого будет использоваться преобразование %f. Генерируемый текст не будет иметь завершающих нулей в любой дробной части и имеет десятичную точку только если имеются ненулевые цифры дробной части, и если Вы не указали флаг формата #.

printf("%.6g", 31.4);              //печатает 31.4
printf("%.1g", 31.4);              //печатает 3.14e+01

Укажите %n для сохранения количества генерируемых символов (до этого места в формате) в целочисленном объекте, адрес которого указан в следующем аргументе.

printf("abc%n", &x);               //сохранит 3 в переменной x

Укажите %p для генерации внешнего представления указателя на void. Преобразование определено реализацией.

printf("%p", (void *)&x);          //печатает, к примеру, F4C0

Укажите %s для генерации последовательности символов из значений, сохраненных в аргументе C-строки.

printf("%s", "hello");             //печатает hello
printf("%.2s", "hello");           //печатает he

Укажите %% для генерации одного символа процента (%).

printf("%%");                      //печатает %

[Конфигурирование функций вывода библиотеки DLIB]

Возможности вывода в среде IAR (что могут функции printf, sprintf и т. п.) определяются настройками библиотеки DLIB. Доступ к настройкам осуществляется через свойства проекта IAR: Options... -> General Options -> закладка Library Configuration, выпадающий список Library. Настройка на этой закладке влияет не только на printf, но и на другие функции библиотеки DLIB.

IAR-printf-DLIB-Library-Configuration

Возможны 4 варианта на выбор: None, Normal, Full, Custom. Обычно выбирают вариант Full.

None в этом варианте функции вывода недоступны. Вы не можете использовать в программе форматированный вывод printf.

Normal для этого варианта нет поддержки интерфейса языковой локали, не установлена локаль C, нет поддержки дескрипторов файла, нет поддержки многобайтового формата строки в printf и scanf, не поддерживаются шестнадцатеричные числа с плавающей запятой в strtod. Этот вариант работает быстрее и занимает меньше памяти, чем Full, и часто допустим в несложных программах.

Full полная конфигурация runtime библиотеки C/C++. Все, что было недоступно в Normal, теперь поддерживается.

Custom пользовательская конфигурация библиотеки, которая задается внешним подключаемым заголовком (C-header, файл с расширением .h).

Следующая закладка, Library Options, позволяет настроить возможности преобразований для строки форматирования (т. е. как будут обрабатываться спецификации преобразований, начинающиеся знаком %). Можно отдельно задать возможности для printf (функции форматированного вывода) и для scanf (функции форматированного ввода).

IAR-printf-DLIB-Library-Options

Tiny самый быстрый и самый урезанный вариант. Нет поддержки a, A, n, float, long long, нельзя использовать флаги.

Small то же самое, что и Tiny, но можно использовать флаги формата.

Large нет только поддержки a, A, все остальное доступно.

Full доступны все возможности форматированного преобразования.

[Словарик]

format string строка формата - заключенный в двойные кавычки строковый аргумент функции вывода, который содержит в себе спецификации преобразования (помеченные знаком %, например "%i", "%02X") остальных аргументов.

initial shift state начальное состояние смещения

conversion specifications спецификации преобразования - начинающиеся на знак процента (%) закодированные специальным образом правила преобразования в текст аргументов функции вывода.

va_list объектный тип для предоставления контекстной информации, инициализированный va_start и использующий va_arg для доступа к добавочным неименованным аргументам. Применяется в функциях с переменным числом параметров типа printf.

va_start макрос, хранящий начальную контекстную информацию об объекте, определяемом приложением. Имя last-par является именем последнего параметра, задаваемого Вами. Например, last-par будет b для определения функции int f(int a, int b, ...).

va_arg макрос, который передает следующий параметр в порядке, определенном контекстной информацией, указанной в приложении. Дополнительные аргументы должны иметь объектный тип Ty после применения правил для того, чтобы представить параметры в отсутствии прототипа функции.

[Ссылки]

1. IAR EW ARM: как перенаправить вывод printf и putchar.

 

Добавить комментарий


Защитный код
Обновить

Top of Page