![]() |
|
|||
WebMoney: WMZ Z294115950220 WMR R409981405661 WME E134003968233 |
Visa 4274 3200 2453 6495 |
SQLite содержит свое собственное внедрение режима форматирования
последовательности "printf()", доступное через следующие интерфейсы: То же самое основное средство форматирования последовательности
также используется внутренне SQLite. Почему SQLite имеет собственный частный встроенный printf()?
Почему бы не использовать printf()
от стандартной библиотеки для C? Несколько причин: При помощи его собственного встроенного внедрения SQLite
гарантирует, что вывод будет тем же самым на всех платформах и во всех
LOCALE. Это важно для последовательности и для тестирования. Это было бы
проблематично, если бы одна машина дала ответ "5.25e+08", а другая
"5.250e+008". Оба ответа правильны, но лучше, когда SQLite всегда дает
тот же самый ответ. Мы не знаем ни о каком способе пользоваться стандартной библиотекой
printf() C, чтобы осуществить SQL-функцию
format() в SQLite. Встроенный printf() может быть легко адаптирован к
этой задаче, как бы то ни было. printf() в SQLite поддерживает новые нестандартные типы замены
(%q,
%Q,
%w и
%z)
и увеличенное поведение замены (%s и %z),
которые полезны внутренне для SQLite и для запросов, используя SQLite.
Стандартная библиотека printf() не может обычно
расширяться таким образом. Через sqlite3_mprintf() и
sqlite3_vmprintf() встроенный printf()
поддерживает способность отдать череду произвольных длин в буфер памяти,
полученный из sqlite3_malloc64().
Это более безопасно и менее подвержено ошибкам, чем попытка предварительно
вычислить верхнее ограничение размера на последовательность результата,
ассигновать соответственно размерный буфер, а
затем вызвать snprintf(). SQLite-printf() поддерживает новый флаг
"alternate-form-2". Он изменяет обработку преобразований с плавающей запятой
тонкими способами так, чтобы вывод всегда был SQL-совместимым текстовым
представлением числа с плавающей запятой, этого невозможно достигнуть со
стандартной библиотекой printf(). Для замен последовательности
alternate-form-2 заставляет ширину и точность быть измеренной в знаках вместо
байтов, что упрощает обработку последовательностей, содержащих
мультибайтные знаки UTF8. У встроенного SQLite есть варианты времени компиляции, такие как
SQLITE_PRINTF_PRECISION_LIMIT, которые обеспечивают защиту против атак
denial-of-service для применений, которые выставляют функциональность
printf() пользователям, которым не доверяют. Использование встроенного printf() означает, что у SQLite есть
меньше зависимости от серверной среды, делая его более портативным.
Честно, наличие встроенного внедрения printf()
также идет с некоторыми недостатками. Встроенный printf() использует дополнительное кодовое пространство
(приблизительно 7800 байтов на GCC 5.4 с -Os). С плавающей запятой к текстовой конверсионной подфункции для
встроенного printf() ограничивается в точности 16 значительными цифрами или
26 значительными цифрами, если использован "!" alternate-form-2.
Каждый IEEE 754 double может быть представлен точно как десятичное
значение, но для многих double точное десятичное представление требует
больше, чем 16 или 26 значительных цифр. SQLite printf() отдает только первые
16 или 26 значительных цифр, потому что это может быть сделано эффективно
и потому что 16 десятичных цифр достаточно, чтобы отличить каждое возможнле
значение double. Используйте
десятичное расширение,
чтобы получить точный десятичный эквивалент double
для редких случаев, где это требуется. Порядок буферного указателя и параметров размера буфера во встроенном
snprintf() полностью изменен от порядка, используемого во
внедрениях стандартной библиотеки. Встроенный printf() не обращается с позиционными модификаторами
ссылки posix, которые позволяют порядку аргументов printf()
отличаться от порядка %-подстановок. Во встроенном printf() порядок
аргументов должен точно соответствовать порядку %-подстановок. Несмотря на недостатки, разработчики полагают, что иметь встроенный
printf() в SQLite это полезно. Строка формата для printf() является шаблоном для произведенной
последовательности. Замены сделаны каждый раз, когда символ "%"
появляется в строке формата. "%" сопровождается одним или более
дополнительными знаками, которые описывают замену.
У каждой замены есть следующий формат: Все замены начинаются с единственного "%" и заканчиваются
единственным символом текста. Другие элементы замены дополнительные. Чтобы включать единственный символ "%" в вывод, поместите два
последовательных знака "%" в шаблон. Следующая диаграмма показывает типы замены, поддержанные SQLite: Длина значения аргумента может быть определена одним или более символами,
которые появляются только до символа типа замены. В SQLite длина имеет
значение только для целых типов. Длина проигнорирована для SQL-функции
format(),
которая всегда использует 64-битные значения.
Следующая таблица показывает спецификаторы длины, позволенные SQLite: Только "ll" когда-либо имеет значение для SQLite. И это имеет значение,
только используя интерфейсы языка C. Область ширины определяет минимальную ширину значения, которое заменяют, в
выводе. Если последовательность или число, которое написано в вывод, короче,
чем ширина, то значение дополнено. Дополнение по умолчанию слева (значение
выровнено по правому знаку). Если использован флаг "-",
то дополнение справа, и значение выровнено по левому краю. Ширина измерена в байтах по умолчанию. Однако, если указан флаг "!",
ширина задана в знаках. Это имеет значение только для
мультибайтных знаков utf-8. Если ширина это единственный символ "*"
вместо числа, то фактическое значение ширины прочитано как целое число
из списка аргументов. Если прочитанное значение отрицательное,
то абсолютное значение используется для ширины, и оно выровнено налево,
как будто применен флаг "-". Если значение, которым заменяют, больше, чем ширина, то полное значение
добавляется к выводу. Другими словами, ширина это минимальная ширина
значения в выводе. Область точности, если это присутствует, должна следовать за шириной,
отделенная единственной ".". Если нет никакой ширины, то ".",
которая вводит точность, следует немедленно за любым флагом (если
есть) или начальным "%". Для замен последовательности (%s, %z, %q, %Q или %w)
точность это число байт или символов, используемых от аргумента.
Число это байты по умолчанию, но является знаками, если указать "!".
Если нет никакой точности, то заменяют всей последовательностью. Примеры:
"%.3s" заменяет первыми 3 байтами последовательности аргумента.
"%!.3s" заменяет первыми тремя знаками последовательности аргумента. Для замен целого числа (%d, %i, %x, %X, %o и %p)
точность определяет минимальное количество цифр, чтобы показать.
Начальные нули добавляются при необходимости, чтобы расширить вывод
до минимального количества цифр. Для замен с плавающей запятой (%e, %E, %f, %g, %G)
точность определяет количество цифр, чтобы показать справа
от десятичной точки. Для замены символа (%c) точность N больше, чем 1 предписывает повторить
символ N раз. Это нестандартное расширение SQLite. Если точность это единственный символ "*" вместо числа, то фактическое
значение точности прочитано как целое число из списка аргументов. Флаги состоят из ноля или большего количества знаков, которые немедленно
следуют за "%", который вводит замену.
Различные флаги и их значения следующие: Основной движок форматирования последовательности это функция
sqlite3VXPrintf() в исходном файле
printf.c.
Все различные интерфейсы вызывают (иногда косвенно) эту основную функцию.
sqlite3VXPrintf() началась как код, написанный первым автором SQLite
(Hipp), когда он был аспирантом в Университете Дюка в
конце 1980-х. Hipp сохранял этот printf()
в его личном комплекте инструментов, пока он не начал работать над SQLite в
2000. Код был включен в исходное дерево SQLite
2000-10-08
в SQLite version 1.0.9. Fossil Version Control System
использует свой собственный printf(), который получен из ранней версии
SQLite printf(), но те два внедрения с тех пор отличались. Функция sqlite3_snprintf()
имеет свой буферный указатель и аргументы размера буфера, полностью
измененные от того, что найдено в стандартной библиотеке для C snprintf().
Это вызвано тем, что не было никакого snprintf()
в стандартной библиотеке для C, когда Hipp сначала осуществлял свою
версию, и он выбрал другой порядок, чем проектировщики
стандартной библиотеки для C.
Choose any three.
1. Обзор
1.1. Преимущества
1.2. Недостатки
2. Форматирование деталей
%[flags][width][.precision][length]type
2.1. Типы замены
Тип замены Значение
% Два символа "%" в строке подряд переведены в единственный "%"
в выводе, не заменяя никакими значениями. d, i
Аргумент это целое число со знаком, которое
показано в десятичном числе. u
Аргумент это целое без знака, которое
показано в десятичном числе. f
Аргумент это double, которое показано в десятичном числе. e, E
Аргумент это double, которое показано в экспоненциальном представлении.
Символ экспоненты 'e' или 'E' в зависимости от типа. g, G
Аргумент это double, которое показано
в нормальной десятичной записи или (если экспонента не близка к
нолю) в экспоненциальном представлении. x, X
Аргумент это double, которое показано в шестнадцатеричном виде.
Шестнадцатеричные строчные буквы используются для %x,
верхний регистр используется для %X. o Аргумент это целое число, которое
показано в октальном виде. s, z
Аргумент это законченная нолем последовательность, которая показана, или
нулевой указатель, который рассматривают как пустую строку.
Для типа %z в интерфейсе языка C sqlite3_free()
вызван после того, как это было скопировано в вывод. Подстановки %s и %z
идентичны для SQL printf(), параметр NULL рассматривают как пустую строку.
Подстановка %s универсальна среди функций printf, но %z и безопасная
обработка нулевых указателей это улучшения SQLite, не
найденные в другом printf().c
Для интерфейсов языка C аргумент это целое число, которое
интерпретируется как символ. Для
функции format() аргумент это строка, из которой первый
символ извлечен и показан. p
Аргумент это указатель, который показан как шестнадцатеричный адрес.
Так как у языка SQL нет понятия указателя, %p для функции
format() работает как %x. n
Аргумент это указатель на целое число. Ничто не показано для этого типа
замены. Вместо этого целое число, на которое указывает аргумент, переписано
количеством знаков в произведенной последовательности, которые следуют из
всех символов формата налево от %n. q, Q
Аргумент это законченная нолем последовательность.
Последовательность печатается со всеми одинарными кавычками, удвоенными так,
чтобы последовательность могла безопасно появиться в строковом литерале SQL.
Тип замены %Q также помещает одинарные кавычки на оба конца
последовательности, которой заменяют.
Если аргумент %Q нулевой указатель, вывод неэкранированный "NULL".
Другими словами, нулевой указатель производит NULL SQL, и ненулевой указатель
производит действительный строковый литерал SQL. Если аргумент %q
нулевой указатель, никакой вывод не произведен. Таким образом нулевой
указатель к %q совпадает с пустой строкой.
Для этих замен точность это число байтов или знаков, взятых от аргумента,
а не число байтов или знаков, которые написаны в вывод.
%q и %Q улучшения SQLite, не найденные в большей
части других printf().w
Эта замена работает как %q за исключением того, что это удваивает все знаки
двойной кавычки (") вместо одинарных кавычек, делая результат подходящим для
использования с именем идентификатора в двойных кавычках в SQL-операторе.
Замена %w это улучшение SQLite, не найденное в большей
части других printf().2.2.
Дополнительная область длины
Спецификатор длины Смысл (умолчание)
"int" или "unsigned int". 32 бита на всех современных системах. l "long int" или "long unsigned int".
32 бита на всех современных системах. ll
"long long int", "long long unsigned", "sqlite3_int64" или
"sqlite3_uint64". Это 64-битные целые числа на всех современных системах.
2.3.
Дополнительная область ширины
2.4.
Дополнительная область точности
2.5.
Область флагов вариантов
3.
Внедрение и история