nanoprintf ist eine unbelastete Implementierung von snprintf und vsnprintf für eingebettete Systeme, die bei vollständiger Aktivierung die Einhaltung des C11-Standards anstreben. Die primären Ausnahmen sind Gleitkommazahlen, wissenschaftliche Notationen ( %e
, %g
, %a
) und die Konvertierungen, die die Existenz von wcrtomb
erfordern. Die binäre Ganzzahlausgabe C23 wird optional gemäß N2630 unterstützt. Sicherheitserweiterungen für snprintf und vsnprintf können optional so konfiguriert werden, dass sie bei Pufferüberlaufereignissen gekürzte oder vollständig leere Zeichenfolgen zurückgeben.
Darüber hinaus kann nanoprintf zum Parsen von Formatzeichenfolgen im Printf-Stil verwendet werden, um die verschiedenen Parameter und Konvertierungsspezifizierer zu extrahieren, ohne dass eine tatsächliche Textformatierung erforderlich ist.
nanoprintf nimmt keine Speicherzuweisungen vor und verwendet weniger als 100 Byte Stapel. Je nach Konfiguration werden auf einer Cortex-M0-Architektur zwischen ca. 740 und 2640 Byte Objektcode kompiliert.
Der gesamte Code ist für maximale Compilerkompatibilität in einem minimalen C99-Dialekt geschrieben, lässt sich bei den höchsten Warnstufen auf clang + gcc + msvc sauber kompilieren, verursacht keine Probleme mit UBsan oder Asan und wird ausführlich auf 32-Bit- und 64-Bit-Architekturen getestet . nanoprintf enthält zwar C-Standard-Header, verwendet sie jedoch nur für C99-Typen und Argumentlisten; Es werden keine Aufrufe an stdlib/libc vorgenommen, mit Ausnahme etwaiger interner arithmetischer Aufrufe großer Ganzzahlen, die Ihr Compiler möglicherweise ausgibt. Wie üblich sind einige Windows-spezifische Header erforderlich, wenn Sie nativ für msvc kompilieren.
nanoprintf ist eine einzelne Header-Datei im Stil der stb-Bibliotheken. Der Rest des Repositorys besteht aus Tests und Gerüsten und ist für die Verwendung nicht erforderlich.
nanoprintf ist statisch konfigurierbar, sodass Benutzer ein Gleichgewicht zwischen Größe, Compiler-Anforderungen und Funktionsumfang finden können. Gleitkommakonvertierung, „große“ Längenmodifikatoren und Größenrückschreibung sind alle konfigurierbar und werden nur kompiliert, wenn dies ausdrücklich angefordert wird. Weitere Informationen finden Sie unter Konfiguration.
Fügen Sie einer Ihrer Quelldateien den folgenden Code hinzu, um die nanoprintf-Implementierung zu kompilieren:
// define your nanoprintf configuration macros here (see "Configuration" below) #define NANOPRINTF_IMPLEMENTATION #include "path/to/nanoprintf.h"
Fügen Sie dann in jede Datei, in der Sie nanoprintf verwenden möchten, einfach den Header ein und rufen Sie die npf_-Funktionen auf:
#include "nanoprintf.h" void print_to_uart(void) { npf_pprintf(&my_uart_putc, NULL, "Hello %s%c %d %u %fn", "worl", 'd', 1, 2, 3.f); } void print_to_buf(void *buf, unsigned len) { npf_snprintf(buf, len, "Hello %s", "world"); }
Weitere Einzelheiten finden Sie in den Beispielen „Nanoprintf direkt verwenden“ und „Nanoprintf umschließen“.
Ich wollte ein Public-Domain-Drop-In-PrintF mit einer einzelnen Datei, das in der Minimalkonfiguration (Bootloader usw.) weniger als 1 KB und mit aktiviertem Gleitkomma-Schnickschnack weniger als 3 KB groß ist.
Bei der Firmware-Arbeit möchte ich im Allgemeinen die Zeichenfolgenformatierung von stdio ohne die Anforderungen der Systemaufruf- oder Dateideskriptorschicht; Sie werden in kleinen Systemen, in denen Sie sich in kleine Puffer einloggen oder direkt an einen Bus senden möchten, fast nie benötigt. Außerdem sind viele eingebettete stdio-Implementierungen größer oder langsamer als nötig – das ist wichtig für die Arbeit mit dem Bootloader. Wenn Sie keine Systemaufrufe oder stdio-Schnickschnack benötigen, können Sie einfach nanoprintf und nosys.specs
verwenden und Ihren Build verschlanken.
Dieser Code ist auf Größe optimiert, nicht auf Lesbarkeit oder Struktur. Leider erhöhen Modularität und „Sauberkeit“ (was auch immer das bedeutet) in diesem kleinen Maßstab den Mehraufwand, sodass der Großteil der Funktionalität und Logik in npf_vpprintf
zusammengefasst wird. So sollte normaler eingebetteter Systemcode nicht aussehen; Es ist #ifdef
Suppe und schwer zu verstehen, und ich entschuldige mich, wenn Sie bei der Implementierung herumstochern müssen. Hoffentlich dienen Ihnen die verschiedenen Tests als Orientierungshilfe, wenn Sie sich damit herumschlagen.
Alternativ sind Sie vielleicht ein wesentlich besserer Programmierer als ich! In diesem Fall helfen Sie mir bitte, diesen Code kleiner und sauberer zu machen, ohne den Footprint zu vergrößern, oder bringen Sie mich in die richtige Richtung. :) :)
nanoprintf hat 4 Hauptfunktionen:
npf_snprintf
: Verwendung wie snprintf.
npf_vsnprintf
: Verwendung wie vsnprintf ( va_list
Unterstützung).
npf_pprintf
: Verwendung wie printf mit einem Schreibrückruf pro Zeichen (Semihosting, UART usw.).
npf_vpprintf
: Wird wie npf_pprintf
verwendet, benötigt jedoch eine va_list
.
Die pprintf
Varianten benötigen einen Rückruf, der das zu druckende Zeichen und einen vom Benutzer bereitgestellten Kontextzeiger empfängt.
Übergeben Sie NULL
oder nullptr
an npf_[v]snprintf
, um nichts zu schreiben und nur die Länge der formatierten Zeichenfolge zurückzugeben.
nanoprintf stellt weder printf
noch putchar
selbst bereit; Diese werden als Dienste auf Systemebene angesehen und nanoprintf ist eine Dienstprogrammbibliothek. nanoprintf ist jedoch hoffentlich ein guter Baustein zum Erstellen Ihres eigenen printf
.
Die nanoprintf-Funktionen geben alle denselben Wert zurück: die Anzahl der Zeichen, die entweder an den Callback gesendet wurden (für npf_pprintf) oder die Anzahl der Zeichen, die in den Puffer geschrieben worden wären, wenn ausreichend Platz vorhanden wäre. Das Nullterminator-0-Byte ist nicht Teil der Zählung.
Der C-Standard ermöglicht es den printf-Funktionen, negative Werte zurückzugeben, falls Zeichenfolgen- oder Zeichenkodierungen nicht durchgeführt werden können oder wenn der Ausgabestream auf EOF trifft. Da nanoprintf Betriebssystemressourcen wie Dateien nicht berücksichtigt und den Längenmodifikator l
für wchar_t
Unterstützung nicht unterstützt, handelt es sich bei allen Laufzeitfehlern entweder um interne Fehler (bitte melden!) oder um eine falsche Verwendung. Aus diesem Grund gibt nanoprintf nur nicht negative Werte zurück, die angeben, wie viele Bytes die formatierte Zeichenfolge enthält (wiederum abzüglich des Nullterminierungsbytes).
nanoprintf verfügt über die folgenden statischen Konfigurationsflags.
NANOPRINTF_USE_FIELD_WIDTH_FORMAT_SPECIFIERS
: Auf 0
oder 1
setzen. Aktiviert Feldbreitenspezifizierer.
NANOPRINTF_USE_PRECISION_FORMAT_SPECIFIERS
: Auf 0
oder 1
setzen. Aktiviert Präzisionsspezifizierer.
NANOPRINTF_USE_FLOAT_FORMAT_SPECIFIERS
: Auf 0
oder 1
setzen. Aktiviert Gleitkommaspezifizierer.
NANOPRINTF_USE_LARGE_FORMAT_SPECIFIERS
: Auf 0
oder 1
setzen. Aktiviert übergroße Modifikatoren.
NANOPRINTF_USE_BINARY_FORMAT_SPECIFIERS
: Auf 0
oder 1
setzen. Aktiviert binäre Spezifizierer.
NANOPRINTF_USE_WRITEBACK_FORMAT_SPECIFIERS
: Auf 0
oder 1
setzen. Aktiviert %n
für das Zurückschreiben.
NANOPRINTF_VISIBILITY_STATIC
: Optionale Definition. Markiert Prototypen als static
für die Sandbox von Nanoprintf.
Wenn keine Konfigurationsflags angegeben sind, verwendet nanoprintf standardmäßig „vernünftige“ eingebettete Werte, um hilfreich zu sein: Floats sind aktiviert, aber Rückschreib-, Binär- und Großformatierer sind deaktiviert. Wenn Konfigurationsflags explizit angegeben werden, verlangt nanoprintf, dass alle Flags explizit angegeben werden.
Wenn eine deaktivierte Formatspezifiziererfunktion verwendet wird, findet keine Konvertierung statt und stattdessen wird einfach die Formatspezifiziererzeichenfolge gedruckt.
nanoprintf hat die folgenden Gleitkomma-spezifischen Konfigurationsdefinitionen.
NANOPRINTF_CONVERSION_BUFFER_SIZE
: Optional, standardmäßig 23
. Legt die Größe eines Zeichenpuffers fest, der zum Speichern des konvertierten Werts verwendet wird. Stellen Sie eine größere Zahl ein, um das Drucken von Gleitkommazahlen mit mehr Zeichen zu ermöglichen. Die Puffergröße umfasst zwar den ganzzahligen Teil, den Bruchteil und das Dezimaltrennzeichen, jedoch nicht das Vorzeichen und die Füllzeichen. Wenn die Nummer nicht in den Puffer passt, wird eine err
ausgegeben. Seien Sie bei großen Größen vorsichtig, da der Konvertierungspuffer im Stapelspeicher reserviert wird.
NANOPRINTF_CONVERSION_FLOAT_TYPE
: Optional, standardmäßig unsigned int
. Legt den Ganzzahltyp fest, der für den Float-Konvertierungsalgorithmus verwendet wird, der die Konvertierungsgenauigkeit bestimmt. Kann auf einen beliebigen Ganzzahltyp ohne Vorzeichen festgelegt werden, z. B. uint64_t
oder uint8_t
.
Standardmäßig verhalten sich npf_snprintf und npf_vsnprintf gemäß dem C-Standard: Der bereitgestellte Puffer wird gefüllt, aber nicht überlaufen. Wenn die Zeichenfolge den Puffer überlaufen hätte, wird ein Null-Terminator-Byte in das letzte Byte des Puffers geschrieben. Wenn der Puffer null
ist oder die Größe Null hat, werden keine Bytes geschrieben.
Wenn Sie NANOPRINTF_SNPRINTF_SAFE_EMPTY_STRING_ON_OVERFLOW
definieren und Ihre Zeichenfolge größer als Ihr Puffer ist, wird das erste Byte des Puffers mit einem Null-Terminator-Byte überschrieben. Dies ähnelt im Geiste dem snprintf_s von Microsoft.
In allen Fällen gibt nanoprintf die Anzahl der Bytes zurück, die in den Puffer geschrieben worden wären, wenn genügend Platz vorhanden wäre. Dieser Wert berücksichtigt nicht das Null-Terminator-Byte gemäß dem C-Standard.
nanoprintf verwendet nur Stapelspeicher und keine Parallelitätsprimitive, sodass es intern seine Ausführungsumgebung nicht wahrnimmt. Dies macht es sicher, gleichzeitig aus mehreren Ausführungskontexten aufzurufen oder einen npf_
Aufruf durch einen anderen npf_
Aufruf (z. B. einen ISR oder etwas Ähnliches) zu unterbrechen. Wenn Sie npf_pprintf
gleichzeitig mit demselben npf_putc
-Ziel verwenden, liegt es an Ihnen, die Richtigkeit Ihres Rückrufs sicherzustellen. Wenn Sie npf_snprintf
von mehreren Threads auf denselben Puffer übertragen, kommt es zu einem offensichtlichen Datenwettlauf.
Wie printf
erwartet nanoprintf
eine Konvertierungsspezifikationszeichenfolge der folgenden Form:
[flags][field width][.precision][length modifier][conversion specifier]
Flaggen
Keines oder mehrere der folgenden Dinge:
0
: Füllen Sie das Feld mit führenden Nullen auf.
-
: Richten Sie das Konvertierungsergebnis im Feld linksbündig aus.
+
: Vorzeichenbehaftete Konvertierungen beginnen immer mit +
oder -
Zeichen.
: (Leerzeichen) Ein Leerzeichen wird eingefügt, wenn das erste konvertierte Zeichen kein Zeichen ist.
#
: Schreibt zusätzliche Zeichen ( 0x
für Hexadezimalzahl, .
für leere Gleitkommazahlen, „0“ für leere Oktalzahlen usw.).
Feldbreite (falls aktiviert)
Eine Zahl, die die gesamte Feldbreite für die Konvertierung angibt, fügt Auffüllung hinzu. Wenn die Feldbreite *
ist, wird die Feldbreite aus der nächsten Variable gelesen.
Präzision (falls aktiviert)
Mit einem vorangestellten .
, eine Zahl, die die Genauigkeit der Zahl oder Zeichenfolge angibt. Wenn die Genauigkeit *
ist, wird die Genauigkeit aus dem nächsten Vararg gelesen.
Längenmodifikator
Keines oder mehrere der folgenden Dinge:
h
: Verwenden Sie short
für Integral- und Write-Back-Vararg-Breite.
L
: Verwenden Sie long double
für die Float-Vararg-Breite (Hinweis: Es wird dann in double
umgewandelt)
l
: Verwenden Sie die Vararg-Breite long
, double
oder wide.
hh
: Verwenden Sie char
für die Integral- und Write-Back-Vararg-Breite.
ll
: (großer Spezifizierer) Verwenden Sie long long
für Integral- und Write-Back-Vararg-Breite.
j
: (großer Spezifizierer) Verwenden Sie die Typen [u]intmax_t
für die Integral- und Write-Back-Vararg-Breite.
z
: (großer Spezifizierer) Verwenden Sie die size_t
-Typen für die Integral- und Write-Back-Vararg-Breite.
t
: (großer Spezifizierer) Verwenden Sie die Typen ptrdiff_t
für die Integral- und Write-Back-Vararg-Breite.
Konvertierungsspezifizierer
Genau eines der folgenden:
%
: Prozentzeichen-Literal
c
: Charakter
s
: Nullterminierte Zeichenfolgen
i
/ d
: Vorzeichenbehaftete ganze Zahlen
u
: Ganzzahlen ohne Vorzeichen
o
: Vorzeichenlose oktale Ganzzahlen
x
/ X
: Vorzeichenlose hexadezimale Ganzzahlen
p
: Zeiger
n
: Schreiben Sie die Anzahl der geschriebenen Bytes in den Zeiger vararg
f
/ F
: Gleitkomma-Dezimalzahl
e
/ E
: Wissenschaftlicher Gleitkommawert (nicht implementiert, gibt Gleitkomma-Dezimalzahl aus)
g
/ G
: Kürzester Gleitkommawert (nicht implementiert, gibt Gleitkomma-Dezimalzahl aus)
a
/ A
: Gleitkomma-Hexadezimalwert (nicht implementiert, gibt Gleitkomma-Dezimalzahl aus)
b
/ B
: Binäre ganze Zahlen
Die Gleitkommakonvertierung erfolgt durch Extrahieren der ganzzahligen und gebrochenen Teile der Zahl in zwei separate ganzzahlige Variablen. Für jeden Teil wird der Exponent dann von der Basis 2 auf die Basis 10 skaliert, indem die Mantisse iterativ entsprechend durch 2 und 5 multipliziert und dividiert wird. Die Reihenfolge der Skalierungsoperationen wird dynamisch (je nach Wert) ausgewählt, um möglichst viele der höchstwertigen Bits der Mantisse beizubehalten. Je weiter der Wert vom Dezimaltrennzeichen entfernt ist, desto größer wird der Fehler bei der Skalierung. Bei einer Konvertierungs-Ganzzahltypbreite von durchschnittlich N
Bits behält der Algorithmus eine Genauigkeit von N - log2(5)
oder N - 2.322
Bits bei. Darüber hinaus werden ganzzahlige Teile bis zu 2 ^^ N - 1
und Bruchteile mit bis zu N - 2.322
Bits nach dem Dezimaltrennzeichen perfekt umgewandelt, ohne dass Bits verloren gehen.
Da der Float -> Fixed-Code mit den rohen Float-Wertbits arbeitet, werden keine Gleitkommaoperationen ausgeführt. Dadurch kann nanoprintf Floats auf Soft-Float-Architekturen wie Cortex-M0 effizient formatieren, mit oder ohne Optimierungen wie „Fast Math“ identisch funktionieren und den Code-Footprint minimieren.
Die Spezifizierer %e
/ %E
, %a
/ %A
und %g
/ %G
werden analysiert, aber nicht formatiert. Bei Verwendung ist die Ausgabe identisch mit der Ausgabe von %f
/ %F
. Pull-Anfragen willkommen! :) :)
Es gibt keine Unterstützung für Breitzeichen: Die Felder %lc
und %ls
erfordern, dass das Argument wie durch einen Aufruf von wcrtomb in ein Zeichenarray konvertiert wird. Wenn Gebietsschema- und Zeichensatzkonvertierungen beteiligt sind, ist es schwierig, den Namen „Nano“ beizubehalten. Dementsprechend verhalten sich %lc
und %ls
wie %c
bzw. %s
.
Derzeit sind die einzigen unterstützten Float-Konvertierungen die Dezimalformen: %f
und %F
. Pull-Anfragen willkommen!
Der CI-Build ist so eingerichtet, dass er gcc und nm verwendet, um die kompilierte Größe jeder Pull-Anfrage zu messen. Aktuelle Ausführungen finden Sie in der Auftragsausgabe „Größenberichte“ von Presubmit Checks.
Die folgenden Größenmessungen beziehen sich auf den Cortex-M0-Build.
Configuration "Minimal": arm-none-eabi-gcc -c -x c -Os -I/__w/nanoprintf/nanoprintf -o npf.o -mcpu=cortex-m0 -DNANOPRINTF_IMPLEMENTATION -DNANOPRINTF_USE_FIELD_WIDTH_FORMAT_SPECIFIERS=0 -DNANOPRINTF_USE_PRECISION_FORMAT_SPECIFIERS=0 -DNANOPRINTF_USE_FLOAT_FORMAT_SPECIFIERS=0 -DNANOPRINTF_USE_LARGE_FORMAT_SPECIFIERS=0 -DNANOPRINTF_USE_BINARY_FORMAT_SPECIFIERS=0 -DNANOPRINTF_USE_WRITEBACK_FORMAT_SPECIFIERS=0 - arm-none-eabi-nm --print-size --size-sort npf.o 00000046 00000002 t npf_bufputc_nop 00000048 00000010 t npf_putc_cnt 00000032 00000014 t npf_bufputc 00000270 00000016 T npf_pprintf 000002cc 00000016 T npf_snprintf 00000000 00000032 t npf_utoa_rev 00000286 00000046 T npf_vsnprintf 00000058 00000218 T npf_vpprintf Total size: 0x2e2 (738) bytes Configuration "Binary": arm-none-eabi-gcc -c -x c -Os -I/__w/nanoprintf/nanoprintf -o npf.o -mcpu=cortex-m0 -DNANOPRINTF_IMPLEMENTATION -DNANOPRINTF_USE_FIELD_WIDTH_FORMAT_SPECIFIERS=0 -DNANOPRINTF_USE_PRECISION_FORMAT_SPECIFIERS=0 -DNANOPRINTF_USE_FLOAT_FORMAT_SPECIFIERS=0 -DNANOPRINTF_USE_LARGE_FORMAT_SPECIFIERS=0 -DNANOPRINTF_USE_BINARY_FORMAT_SPECIFIERS=1 -DNANOPRINTF_USE_WRITEBACK_FORMAT_SPECIFIERS=0 - arm-none-eabi-nm --print-size --size-sort npf.o 00000046 00000002 t npf_bufputc_nop 00000048 00000010 t npf_putc_cnt 00000032 00000014 t npf_bufputc 000002a8 00000016 T npf_pprintf 00000304 00000016 T npf_snprintf 00000000 00000032 t npf_utoa_rev 000002be 00000046 T npf_vsnprintf 00000058 00000250 T npf_vpprintf Total size: 0x31a (794) bytes Configuration "Field Width + Precision": arm-none-eabi-gcc -c -x c -Os -I/__w/nanoprintf/nanoprintf -o npf.o -mcpu=cortex-m0 -DNANOPRINTF_IMPLEMENTATION -DNANOPRINTF_USE_FIELD_WIDTH_FORMAT_SPECIFIERS=1 -DNANOPRINTF_USE_PRECISION_FORMAT_SPECIFIERS=1 -DNANOPRINTF_USE_FLOAT_FORMAT_SPECIFIERS=0 -DNANOPRINTF_USE_LARGE_FORMAT_SPECIFIERS=0 -DNANOPRINTF_USE_BINARY_FORMAT_SPECIFIERS=0 -DNANOPRINTF_USE_WRITEBACK_FORMAT_SPECIFIERS=0 - arm-none-eabi-nm --print-size --size-sort npf.o 00000046 00000002 t npf_bufputc_nop 00000048 00000010 t npf_putc_cnt 00000032 00000014 t npf_bufputc 000004fe 00000016 T npf_pprintf 0000055c 00000016 T npf_snprintf 00000000 00000032 t npf_utoa_rev 00000514 00000048 T npf_vsnprintf 00000058 000004a6 T npf_vpprintf Total size: 0x572 (1394) bytes Configuration "Field Width + Precision + Binary": arm-none-eabi-gcc -c -x c -Os -I/__w/nanoprintf/nanoprintf -o npf.o -mcpu=cortex-m0 -DNANOPRINTF_IMPLEMENTATION -DNANOPRINTF_USE_FIELD_WIDTH_FORMAT_SPECIFIERS=1 -DNANOPRINTF_USE_PRECISION_FORMAT_SPECIFIERS=1 -DNANOPRINTF_USE_FLOAT_FORMAT_SPECIFIERS=0 -DNANOPRINTF_USE_LARGE_FORMAT_SPECIFIERS=0 -DNANOPRINTF_USE_BINARY_FORMAT_SPECIFIERS=1 -DNANOPRINTF_USE_WRITEBACK_FORMAT_SPECIFIERS=0 - arm-none-eabi-nm --print-size --size-sort npf.o 00000046 00000002 t npf_bufputc_nop 00000048 00000010 t npf_putc_cnt 00000032 00000014 t npf_bufputc 00000560 00000016 T npf_pprintf 000005bc 00000016 T npf_snprintf 00000000 00000032 t npf_utoa_rev 00000576 00000046 T npf_vsnprintf 00000058 00000508 T npf_vpprintf Total size: 0x5d2 (1490) bytes Configuration "Float": arm-none-eabi-gcc -c -x c -Os -I/__w/nanoprintf/nanoprintf -o npf.o -mcpu=cortex-m0 -DNANOPRINTF_IMPLEMENTATION -DNANOPRINTF_USE_FIELD_WIDTH_FORMAT_SPECIFIERS=0 -DNANOPRINTF_USE_PRECISION_FORMAT_SPECIFIERS=1 -DNANOPRINTF_USE_FLOAT_FORMAT_SPECIFIERS=1 -DNANOPRINTF_USE_LARGE_FORMAT_SPECIFIERS=0 -DNANOPRINTF_USE_BINARY_FORMAT_SPECIFIERS=0 -DNANOPRINTF_USE_WRITEBACK_FORMAT_SPECIFIERS=0 - arm-none-eabi-nm --print-size --size-sort npf.o 00000046 00000002 t npf_bufputc_nop 00000048 00000010 t npf_putc_cnt 00000032 00000014 t npf_bufputc 00000618 00000016 T npf_pprintf 00000674 00000016 T npf_snprintf 00000000 00000032 t npf_utoa_rev 0000062e 00000046 T npf_vsnprintf 00000058 000005c0 T npf_vpprintf Total size: 0x68a (1674) bytes Configuration "Everything": arm-none-eabi-gcc -c -x c -Os -I/__w/nanoprintf/nanoprintf -o npf.o -mcpu=cortex-m0 -DNANOPRINTF_IMPLEMENTATION -DNANOPRINTF_USE_FIELD_WIDTH_FORMAT_SPECIFIERS=1 -DNANOPRINTF_USE_PRECISION_FORMAT_SPECIFIERS=1 -DNANOPRINTF_USE_FLOAT_FORMAT_SPECIFIERS=1 -DNANOPRINTF_USE_LARGE_FORMAT_SPECIFIERS=1 -DNANOPRINTF_USE_BINARY_FORMAT_SPECIFIERS=1 -DNANOPRINTF_USE_WRITEBACK_FORMAT_SPECIFIERS=1 - arm-none-eabi-nm --print-size --size-sort npf.o 0000005a 00000002 t npf_bufputc_nop 0000005c 00000010 t npf_putc_cnt 00000046 00000014 t npf_bufputc 000009da 00000016 T npf_pprintf 00000a38 00000016 T npf_snprintf 00000000 00000046 t npf_utoa_rev 000009f0 00000048 T npf_vsnprintf 0000006c 0000096e T npf_vpprintf Total size: 0xa4e (2638) bytes
So rufen Sie die Umgebung ab und führen Tests aus:
Klonen oder forken Sie dieses Repository.
Führen Sie ./b
im Stammverzeichnis aus (oder py -3 build.py
im Stammverzeichnis für Windows-Benutzer).
Dadurch werden alle Unit-, Konformitäts- und Kompilierungstests für Ihre Hostumgebung erstellt. Bei jedem Testfehler wird ein Exit-Code ungleich Null zurückgegeben.
Die nanoprintf-Entwicklungsumgebung verwendet cmake und ninja. Wenn Sie diese in Ihrem Pfad haben, wird ./b
sie verwenden. Wenn nicht, lädt ./b
sie herunter und stellt sie in path/to/your/nanoprintf/external
bereit.
nanoprintf verwendet GitHub-Aktionen für alle Continuous-Integration-Builds. Die GitHub-Linux-Builds verwenden dieses Docker-Image aus meinem Docker-Repository.
Die Matrix erstellt [Debug, Release] x [32-Bit, 64-Bit] x [Mac, Windows, Linux] x [gcc, clang, msvc], abzüglich der 32-Bit-Clang-Mac-Konfigurationen.
Eine Testsuite ist eine Abzweigung der printf-Testsuite, die vom MIT lizenziert ist. Es existiert als Submodul für Lizenzierungszwecke – nanoprintf ist Public Domain, daher ist diese spezielle Testsuite optional und standardmäßig ausgeschlossen. Um es zu erstellen, rufen Sie es ab, indem Sie Submodule aktualisieren und das Flag --paland
zu Ihrem ./b
hinzufügen. Es ist überhaupt nicht erforderlich, nanoprintf zu verwenden.
Die Grundidee der Float-zu-Int-Konvertierung wurde von Wojciech Mułas festem Algorithmus „float -> 64:64“ inspiriert und durch Hinzufügen dynamischer Skalierung und konfigurierbarer Ganzzahlbreite von Oskars Rubenis weiter erweitert.
Ich habe die printf-Testsuite auf nanoprintf portiert. Es stammt ursprünglich aus der Codebasis des Mpaland-Printf-Projekts, wurde aber von Eyal Rozenberg und anderen übernommen und verbessert. (Nanoprintf hat viele eigene Tests, diese sind aber auch sehr gründlich und sehr gut!)
Die binäre Implementierung basiert auf den Anforderungen des N2630-Vorschlags von Jörg Wunsch und wird hoffentlich in C23 übernommen!