nanoprintf est une implémentation libre de snprintf et vsnprintf pour les systèmes embarqués qui, lorsqu'ils sont entièrement activés, visent la conformité à la norme C11. Les principales exceptions sont la notation scientifique à virgule flottante ( %e
, %g
, %a
) et les conversions qui nécessitent l'existence wcrtomb
. La sortie entière binaire C23 est prise en charge en option selon N2630. Les extensions de sécurité pour snprintf et vsnprintf peuvent éventuellement être configurées pour renvoyer des chaînes coupées ou entièrement vides lors d'événements de dépassement de tampon.
De plus, nanoprintf peut être utilisé pour analyser les chaînes de format de style printf afin d'extraire les différents paramètres et spécificateurs de conversion, sans effectuer de formatage de texte réel.
nanoprintf n'effectue aucune allocation de mémoire et utilise moins de 100 octets de pile. Il compile entre ~ 740 et 2 640 octets de code objet sur une architecture Cortex-M0, selon la configuration.
Tout le code est écrit dans un dialecte minimal de C99 pour une compatibilité maximale avec le compilateur, se compile proprement aux niveaux d'avertissement les plus élevés sur clang + gcc + msvc, ne soulève aucun problème de la part d'UBsan ou Asan et est testé de manière exhaustive sur des architectures 32 bits et 64 bits. . nanoprintf inclut les en-têtes standard C mais ne les utilise que pour les types C99 et les listes d'arguments ; aucun appel n'est effectué dans stdlib / libc, à l'exception des appels arithmétiques internes de grands entiers que votre compilateur pourrait émettre. Comme d'habitude, certains en-têtes spécifiques à Windows sont requis si vous compilez nativement pour msvc.
nanoprintf est un fichier d'en-tête unique dans le style des bibliothèques stb. Le reste du référentiel est constitué de tests et d'échafaudages et n'est pas requis pour l'utilisation.
nanoprintf est configurable de manière statique afin que les utilisateurs puissent trouver un équilibre entre la taille, les exigences du compilateur et l'ensemble des fonctionnalités. La conversion en virgule flottante, les modificateurs de longueur « grands » et la réécriture de taille sont tous configurables et ne sont compilés que si cela est explicitement demandé, voir Configuration pour plus de détails.
Ajoutez le code suivant à l'un de vos fichiers sources pour compiler l'implémentation de nanoprintf :
// define your nanoprintf configuration macros here (see "Configuration" below) #define NANOPRINTF_IMPLEMENTATION #include "path/to/nanoprintf.h"
Ensuite, dans n'importe quel fichier dans lequel vous souhaitez utiliser nanoprintf, incluez simplement l'en-tête et appelez les fonctions npf_ :
#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"); }
Voir les exemples « Utiliser nanoprintf directement » et « Wrap nanoprintf » pour plus de détails.
Je voulais un printf de domaine public à fichier unique qui pesait moins de 1 Ko dans la configuration minimale (chargeurs de démarrage, etc.) et moins de 3 Ko avec les cloches et les sifflets à virgule flottante activés.
Dans le travail sur le micrologiciel, je souhaite généralement le formatage des chaînes de stdio sans les exigences de la couche d'appel système ou de descripteur de fichier ; ils ne sont presque jamais nécessaires dans les petits systèmes où vous souhaitez vous connecter à de petits tampons ou émettre directement vers un bus. En outre, de nombreuses implémentations de stdio intégrées sont plus volumineuses ou plus lentes que nécessaire - ceci est important pour le travail du chargeur de démarrage. Si vous n'avez besoin d'aucun des appels système ou des cloches et sifflets stdio, vous pouvez simplement utiliser nanoprintf et nosys.specs
et affiner votre build.
Ce code est optimisé pour la taille, et non pour la lisibilité ou la structure. Malheureusement, la modularité et la "propreté" (quoi que cela signifie) ajoutent une surcharge à cette petite échelle, de sorte que la plupart des fonctionnalités et de la logique sont regroupées dans npf_vpprintf
. Ce n’est pas à cela que devrait ressembler le code normal des systèmes embarqués ; c'est de la soupe #ifdef
et difficile à comprendre, et je m'excuse si vous devez vous perdre dans la mise en œuvre. Espérons que les différents tests serviront de rails de guidage si vous y bidouillez.
Alternativement, vous êtes peut-être un programmeur bien meilleur que moi ! Dans ce cas, aidez-moi à rendre ce code plus petit et plus propre sans agrandir l'empreinte, ou poussez-moi dans la bonne direction. :)
nanoprintf a 4 fonctions principales :
npf_snprintf
: À utiliser comme snprintf.
npf_vsnprintf
: Utiliser comme vsnprintf (support va_list
).
npf_pprintf
: À utiliser comme printf avec un rappel d'écriture par caractère (semi-hébergement, UART, etc.).
npf_vpprintf
: Utiliser comme npf_pprintf
mais prend une va_list
.
Les variantes pprintf
prennent un rappel qui reçoit le caractère à imprimer et un pointeur contextuel fourni par l'utilisateur.
Passez NULL
ou nullptr
à npf_[v]snprintf
pour ne rien écrire et renvoyez uniquement la longueur de la chaîne formatée.
nanoprintf ne fournit pas printf
ou putchar
lui-même ; ceux-ci sont considérés comme des services au niveau du système et nanoprintf est une bibliothèque d'utilitaires. Nous espérons cependant que nanoprintf est un bon élément de base pour lancer votre propre printf
.
Les fonctions nanoprintf renvoient toutes la même valeur : le nombre de caractères qui ont été envoyés au rappel (pour npf_pprintf) ou le nombre de caractères qui auraient été écrits dans le tampon pour fournir suffisamment d'espace. L’octet 0 de terminaison nulle ne fait pas partie du décompte.
La norme C permet aux fonctions printf de renvoyer des valeurs négatives au cas où les codages de chaînes ou de caractères ne pourraient pas être effectués, ou si le flux de sortie rencontre EOF. Étant donné que nanoprintf ignore les ressources du système d'exploitation telles que les fichiers et ne prend pas en charge le modificateur de longueur l
pour la prise en charge wchar_t
, toute erreur d'exécution est soit un bug interne (veuillez le signaler !), soit une utilisation incorrecte. Pour cette raison, nanoprintf renvoie uniquement des valeurs non négatives représentant le nombre d'octets que contient la chaîne formatée (encore une fois, moins l'octet de terminaison nul).
nanoprintf a les indicateurs de configuration statique suivants.
NANOPRINTF_USE_FIELD_WIDTH_FORMAT_SPECIFIERS
: défini sur 0
ou 1
. Active les spécificateurs de largeur de champ.
NANOPRINTF_USE_PRECISION_FORMAT_SPECIFIERS
: défini sur 0
ou 1
. Active les spécificateurs de précision.
NANOPRINTF_USE_FLOAT_FORMAT_SPECIFIERS
: défini sur 0
ou 1
. Active les spécificateurs à virgule flottante.
NANOPRINTF_USE_LARGE_FORMAT_SPECIFIERS
: défini sur 0
ou 1
. Active les modificateurs surdimensionnés.
NANOPRINTF_USE_BINARY_FORMAT_SPECIFIERS
: défini sur 0
ou 1
. Active les spécificateurs binaires.
NANOPRINTF_USE_WRITEBACK_FORMAT_SPECIFIERS
: défini sur 0
ou 1
. Active %n
pour la réécriture.
NANOPRINTF_VISIBILITY_STATIC
: Définition facultative. Marque les prototypes comme static
dans le bac à sable nanoprintf.
Si aucun indicateur de configuration n'est spécifié, nanoprintf utilisera par défaut des valeurs intégrées "raisonnables" pour tenter d'être utile : les flottants sont activés, mais la réécriture, les binaires et les grands formateurs sont désactivés. Si des indicateurs de configuration sont explicitement spécifiés, nanoprintf exige que tous les indicateurs soient explicitement spécifiés.
Si une fonctionnalité de spécificateur de format désactivée est utilisée, aucune conversion n'aura lieu et la chaîne du spécificateur de format sera simplement imprimée à la place.
nanoprintf a les définitions de configuration spécifiques à virgule flottante suivantes.
NANOPRINTF_CONVERSION_BUFFER_SIZE
: facultatif, la valeur par défaut est 23
. Définit la taille d'un tampon de caractères utilisé pour stocker la valeur convertie. Réglez-le sur un nombre plus grand pour permettre l'impression de nombres à virgule flottante avec plus de caractères. La taille du tampon inclut la partie entière, la partie fractionnaire et le séparateur décimal, mais n'inclut pas le signe ni les caractères de remplissage. Si le numéro ne rentre pas dans le tampon, une err
est imprimée. Soyez prudent avec les grandes tailles car le tampon de conversion est alloué sur la mémoire de la pile.
NANOPRINTF_CONVERSION_FLOAT_TYPE
: facultatif, la valeur par défaut est unsigned int
. Définit le type entier utilisé pour l'algorithme de conversion float, qui détermine la précision de la conversion. Peut être défini sur n'importe quel type entier non signé, comme par exemple uint64_t
ou uint8_t
.
Par défaut, npf_snprintf et npf_vsnprintf se comportent selon la norme C : le tampon fourni sera rempli mais pas dépassé. Si la chaîne aurait dépassé le tampon, un octet de terminaison nul sera écrit dans le dernier octet du tampon. Si le tampon est null
ou de taille nulle, aucun octet ne sera écrit.
Si vous définissez NANOPRINTF_SNPRINTF_SAFE_EMPTY_STRING_ON_OVERFLOW
et que votre chaîne est plus grande que votre tampon, le premier octet du tampon sera écrasé par un octet de terminaison nul. Son esprit est similaire à celui de Microsoft snprintf_s.
Dans tous les cas, nanoprintf renverra le nombre d'octets qui auraient été écrits dans le tampon s'il y avait eu suffisamment de place. Cette valeur ne tient pas compte de l'octet de terminaison nul, conformément à la norme C.
nanoprintf utilise uniquement de la mémoire de pile et aucune primitive de concurrence, donc en interne, il ignore son environnement d'exécution. Cela permet d'appeler en toute sécurité simultanément à partir de plusieurs contextes d'exécution, ou d'interrompre un appel npf_
avec un autre appel npf_
(par exemple, un ISR ou quelque chose du genre). Si vous utilisez npf_pprintf
simultanément avec la même cible npf_putc
, c'est à vous de garantir l'exactitude de votre rappel. Si vous npf_snprintf
depuis plusieurs threads vers le même tampon, vous aurez une course aux données évidente.
Comme printf
, nanoprintf
attend une chaîne de spécification de conversion de la forme suivante :
[flags][field width][.precision][length modifier][conversion specifier]
Drapeaux
Aucun ou plusieurs des éléments suivants :
0
: remplissez le champ avec des zéros en tête.
-
: Justifiez à gauche le résultat de la conversion dans le champ.
+
: Les conversions signées commencent toujours par des caractères +
ou -
.
: (espace) Un caractère espace est inséré si le premier caractère converti n'est pas un signe.
#
: Écrit des caractères supplémentaires ( 0x
pour les hexadécimaux, .
pour les flottants vides, '0' pour les octaux vides, etc.).
Largeur du champ (si activé)
Un nombre qui spécifie la largeur totale du champ pour la conversion, ajoute un remplissage. Si la largeur du champ est *
, la largeur du champ est lue à partir du vararg suivant.
Précision (si activé)
Préfixé par un .
, un nombre qui spécifie la précision du nombre ou de la chaîne. Si la précision est *
, la précision est lue à partir du vararg suivant.
Modificateur de longueur
Aucun ou plusieurs des éléments suivants :
h
: Utilisez short
pour la largeur vararg intégrale et de réécriture.
L
: Utilisez long double
pour la largeur du float vararg (remarque : il sera ensuite converti en double
)
l
: Utilisez une largeur de vararg long
, double
ou large.
hh
: Utilisez char
pour la largeur vararg intégrale et de réécriture.
ll
: (grand spécificateur) Utilisez long long
pour la largeur vararg intégrale et de réécriture.
j
: (grand spécificateur) Utilisez les types [u]intmax_t
pour la largeur vararg intégrale et de réécriture.
z
: (grand spécificateur) Utilisez les types size_t
pour la largeur vararg intégrale et de réécriture.
t
: (grand spécificateur) Utilisez les types ptrdiff_t
pour la largeur vararg intégrale et de réécriture.
Spécificateur de conversion
Exactement l'un des éléments suivants :
%
: littéral de signe de pourcentage
c
: Caractère
s
: chaînes terminées par un caractère nul
i
/ d
: Entiers signés
u
: Entiers non signés
o
: Entiers octaux non signés
x
/ X
: Entiers hexadécimaux non signés
p
: Pointeurs
n
: Ecrit le nombre d'octets écrits sur le pointeur vararg
f
/ F
: Décimal à virgule flottante
e
/ E
: scientifique à virgule flottante (non implémenté, imprime en décimal flottant)
g
/ G
: virgule flottante la plus courte (non implémentée, imprime le nombre décimal flottant)
a
/ A
: hexadécimal à virgule flottante (non implémenté, imprime le nombre décimal flottant)
b
/ B
: Entiers binaires
La conversion en virgule flottante est effectuée en extrayant les parties entières et fractionnaires du nombre en deux variables entières distinctes. Pour chaque partie, l'exposant est ensuite mis à l'échelle de la base 2 à la base 10 en multipliant et en divisant de manière itérative la mantisse par 2 et 5 de manière appropriée. L'ordre des opérations de mise à l'échelle est sélectionné dynamiquement (en fonction de la valeur) pour conserver autant que possible les bits les plus significatifs de la mantisse. Plus la valeur est éloignée du séparateur décimal, plus l'erreur de mise à l'échelle s'accumulera. Avec une largeur de type entier de conversion de N
bits en moyenne, l'algorithme conserve N - log2(5)
ou N - 2.322
bits de précision. De plus, les parties entières jusqu'à 2 ^^ N - 1
et les parties fractionnaires jusqu'à N - 2.322
bits après le séparateur décimal sont parfaitement converties sans perdre aucun bit.
Étant donné que le code float ->fixe opère sur les bits de valeur flottante brute, aucune opération à virgule flottante n'est effectuée. Cela permet à nanoprintf de formater efficacement les flotteurs sur des architectures à flotteur souple comme Cortex-M0, de fonctionner de manière identique avec ou sans optimisations comme les « mathématiques rapides » et de minimiser l'empreinte du code.
Les spécificateurs %e
/ %E
, %a
/ %A
et %g
/ %G
sont analysés mais non formatés. S'il est utilisé, la sortie sera identique à si %f
/ %F
était utilisé. Les demandes de tirage sont les bienvenues ! :)
Il n'existe aucun support pour les caractères larges : les champs %lc
et %ls
nécessitent que l'argument soit converti en un tableau de caractères comme par un appel à wcrtomb. Lorsque les conversions de paramètres régionaux et de jeux de caractères sont impliquées, il est difficile de conserver le nom « nano ». En conséquence, %lc
et %ls
se comportent respectivement comme %c
et %s
.
Actuellement, les seules conversions flottantes prises en charge sont les formes décimales : %f
et %F
. Les demandes de tirage sont les bienvenues !
La version CI est configurée pour utiliser gcc et nm pour mesurer la taille compilée de chaque demande d'extraction. Consultez le résultat de la tâche « taille des rapports » de vérifications préalables pour les exécutions récentes.
Les mesures de taille suivantes sont prises par rapport à la version Cortex-M0.
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
Pour obtenir l'environnement et exécuter des tests :
Clonez ou forkez ce référentiel.
Exécutez ./b
depuis la racine (ou py -3 build.py
depuis la racine, pour les utilisateurs Windows)
Cela créera tous les tests unitaires, de conformité et de compilation pour votre environnement hôte. Tout échec du test renverra un code de sortie différent de zéro.
L'environnement de développement nanoprintf utilise cmake et ninja. Si vous en avez sur votre chemin, ./b
les utilisera. Sinon, ./b
les téléchargera et les déploiera dans path/to/your/nanoprintf/external
.
nanoprintf utilise GitHub Actions pour toutes les versions d'intégration continue. Les versions GitHub Linux utilisent cette image Docker de mon référentiel Docker.
La matrice construit [Debug, Release] x [32 bits, 64 bits] x [Mac, Windows, Linux] x [gcc, clang, msvc], moins les configurations Mac clang 32 bits.
Une suite de tests est un fork de la suite de tests printf, qui est sous licence MIT. Il existe en tant que sous-module à des fins de licence - nanoprintf est du domaine public, cette suite de tests particulière est donc facultative et exclue par défaut. Pour le construire, récupérez-le en mettant à jour les sous-modules et ajoutez l'indicateur --paland
à votre invocation ./b
. Il n’est pas du tout nécessaire d’utiliser nanoprintf.
L'idée de base de la conversion float en int a été inspirée par l'algorithme fixe float -> 64:64 de Wojciech Muła et étendue en ajoutant une mise à l'échelle dynamique et une largeur entière configurable par Oskars Rubenis.
J'ai porté la suite de tests printf sur nanoprintf. Il provenait à l'origine de la base de code du projet mpaland printf mais a été adopté et amélioré par Eyal Rozenberg et d'autres. (Nanoprintf propose plusieurs de ses propres tests, mais ceux-ci sont également très approfondis et très bons !)
L'implémentation binaire est basée sur les exigences spécifiées par la proposition N2630 de Jörg Wunsch, qui, espérons-le, sera acceptée dans C23 !