OVH Cloud OVH Cloud

Equivalent de printf("%#.2X", 2) avec les streams

14 réponses
Avatar
adebaene
Tout est dans le titre...

printf("%#.2X", 2) affiche "0x02" (avec un 0 =E0 gauche pour afficher 2
caract=E8res).

Quel est l'=E9quivalent avec les flux ??
cout<<std::hex<<std::showbase<<?????<<2<<endl;

Que mettre =E0 la place de ????? Ni setw ni setposition ne donnent le
r=E9sultat d=E9sir=E9....
J'ai l'impression que les flux ne permettent pas de controler la
largeur minimale d'afficahge d'un entier. J'ai loup=E9 quelque chose?

Arnaud

4 réponses

1 2
Avatar
kanze
Cyrille wrote:
Michel Michaud wrote:

J'imagine qu'on peut trouver plusieurs raisons, mais essaie
simplement de faire la moindre écriture complexe sans...
Contrairement aux autres manipulateurs, celui-là a une
conséquence sur chaque élément écrit.


Justement : Dès que je veux "out-streamer" un vector / list
/ collection quelconque d'objets, je veux typiquement
afficher tous les éléments avec la même largeur : Etre
obligé de réappliquer setw pour chaque élément est à la fois
lourd dans le code et très probablement pénalisant en terme
de performances.



Attention : si la largueur était persistante, elle jouerait non
seulement sur les éléments, mais aussi sur les séparateurs. Or,
je doute beaucoup que chaque fois que tu veux que l'élément ait
une largueur de 10, tu veux aussi que le virgule séparateur
entre les éléments soit précédés de 9 espaces.

Vous trouverez peut-être votre bonheur dans ces deux librairies:
http://www.boost.org/libs/format/index.html
http://www.boost.org/libs/io/doc/ios_state.html


Quel rapport ?

Le premier permet un formattage à la printf, au moins en ce qui
concerne les options de formattage les plus utiles. Ça peut être
utile, mais dans le cas en question, je ne vois pas ce que ça
apporte par rapporte à un manipulateur bien conçu. Un des gros
avantages de cette version de format, par rapport à la mienne,
d'ailleurs, c'est qu'il supporte l'utilisation des manipulateurs
aussi (je crois). Parce que la plupart du temps, il est
préférable que la spécification du formattage (largueur,
précision, etc.) soit bien séparé du texte.

Le seconde n'est qu'une application du concepte RAII à la
restitution de l'état de formattage à son état initial. Chose
que n'importe qui a bien déjà dans sa boîte à outils, depuis dix
ans ou plus. C'est utile, mais il n'aide en rien la gestion du
formattage même. (Dans mon cas, je dois dire que je n'utilise
prèsque plus mon propre IOSave, étant donné que tous mes
manipulateurs réstaure l'état dans leur déstructeur.)

En fait, pour ce genre de problème, j'utilise toujours un
manipulateur sur mésure -- si c'est des flottants, par exemple,
j'ai une classe prédéfinie FixFmt, qui prend deux paramètres, le
largueur et la précision, et qui permet à écrire des choses
comme:

for ( int i = 0 ; i < v.size() ; ++ i ) {
if ( i != 0 ) {
dest << ", " ;
}
dest << FixFmt( 10, 2 ) << v[ i ] ;
}

Quant aux performances...

FixFmt réstaure tous l'état de formattage dans son déstructeur.
J'effectue donc bien plus de travaille que nécessaire. N'empèche
que je n'ai jamais rencontré un cas où ça avait de
l'importance ; le temps reste négligeable par rapport au temps
nécessaire au formattage d'un flottant. Il ne faut pas exagérer
quand même. (Mais si le profiler disait que c'était un problème,
c'est trivial de déclarer une instance de FixFmt en dehors de la
boucle, et s'en servir.)

--
James Kanze GABI Software
Conseils en informatique orientée objet/
Beratung in objektorientierter Datenverarbeitung
9 place Sémard, 78210 St.-Cyr-l'École, France, +33 (0)1 30 23 00 34



Avatar
Cyrille
Cyrille wrote:

Vous trouverez peut-être votre bonheur dans ces deux librairies:
http://www.boost.org/libs/format/index.html
http://www.boost.org/libs/io/doc/ios_state.html



Quel rapport ?


Euh en fait, je réagissais surtout en rapport avec le titre de ce thread
"Equivalent de printf("%#.2X", 2) avec les streams".
Voilà, la première librairie fournit ça en apportant un formattage à la
printf avec les streams (et un peu plus). Evidemment, c'est une toute
autre philosophie que les manipulateurs standards. J'aurais peut-être dû
répondre en début de thread.

Le seconde n'est qu'une application du concepte RAII à la
restitution de l'état de formattage à son état initial. Chose
que n'importe qui a bien déjà dans sa boîte à outils, depuis dix
ans ou plus. C'est utile, mais il n'aide en rien la gestion du
formattage même. (Dans mon cas, je dois dire que je n'utilise
prèsque plus mon propre IOSave, étant donné que tous mes
manipulateurs réstaure l'état dans leur déstructeur.)


Oui, ok. C'est peu pertinent.


Avatar
Michel Michaud
Dans le message ,
Michel Michaud wrote:
Dans le message
,
a écrit


D'où la question suivante : *Pourquoi* avoir fait un cas
particulier pour la largeur????


J'imagine qu'on peut trouver plusieurs raisons, mais essaie
simplement de faire la moindre écriture complexe sans...
Contrairement aux autres manipulateurs, celui-là a une
conséquence sur chaque élément écrit.


Oui, mais c'est un raisonement circulaire. Avec printf, la
précision a bien un effet sur une chaîne de caractères ; si elle
n'en a pas en C++, c'est sans doute parce que, étant persistant,
ça donne des effets perverses.


Mais, avec printf, les éléments non formatés (entre les %) sont
affichés tel quel. Le formatage par printf est donc finalement très
différent du formatage des flux de C++ et il devient difficile de
justifier un en utilisant l'autre...

De toute façon, on a ce qu'on a dans ISO C++ et si on veut en
ajouter ou utiliser autre chose, it's easy enough :-)

À l'inverse, suppose que fixed et setprecision ne soient pas
persistants... (bah, ça ne serait pas si mal, si c'était setp
au lieu de setprecision :-)


Et qu'est-ce que ça changerait, s'ils n'était pas persistants ?
Tu précèdes normalement chaque champs par un manipulateur quand
même, qui précise comment le formatter d'une manière sémantique
(c-à-d qu'on dit que ses de l'argent, ou un pourcentage, ou...,
et qu'on définit une fois dans le programme comment l'argent et
les pourcentages doivent être formattés).


J'ai l'habitude de tout spécifier à chaque bloc d'écriture, mais
pas à chaque valeur écrite. C'est un habitude qui va bien avec la
persistance de setprecision et fixed en particulier.

Par contre, à l'usage, je considère que setfill aurait avantage à
ne pas être persistant. En fait, pour faire plaisir à tout le
monde l'idéal aurait été d'avoir deux versions de chacun des
manipulateurs : une persistante, une non persistante :

<< fixed << precision(2) << width(5) << fill('*') // non persistant
<< var1
<< setfixed << setp(2) << setw(5) << setfill('*') // persistant
<< var2 << var3

Il y aurait un problème avec cette approche ?

--
Michel Michaud
http://www.gdzid.com
FAQ de fr.comp.lang.c++ :
http://www.cmla.ens-cachan.fr/~dosreis/C++/FAQ/



Avatar
kanze
Michel Michaud wrote:
Dans le message
,
Michel Michaud wrote:
Dans le message
,
a écrit

D'où la question suivante : *Pourquoi* avoir fait un cas
particulier pour la largeur????


J'imagine qu'on peut trouver plusieurs raisons, mais essaie
simplement de faire la moindre écriture complexe sans...
Contrairement aux autres manipulateurs, celui-là a une
conséquence sur chaque élément écrit.


Oui, mais c'est un raisonement circulaire. Avec printf, la
précision a bien un effet sur une chaîne de caractères ; si
elle n'en a pas en C++, c'est sans doute parce que, étant
persistant, ça donne des effets perverses.


Mais, avec printf, les éléments non formatés (entre les %)
sont affichés tel quel. Le formatage par printf est donc
finalement très différent du formatage des flux de C++ et il
devient difficile de justifier un en utilisant l'autre...


Tout à fait. En fait, une des faiblesses, si on veut dire, du
paradigme C++, c'est qu'il ne distingue pas les chaînes champs
d'affichage (les %s du printf) des chaînes remplissage (le texte
en dehors des % du printf). Alors que pour les premières, des
paramètres comme largueur et précision sont significatifs, et
pour les secondes, il ne les faut absolument pas.

Il faut donc que tout paramètre qui affecte une chaîne soit
volatile ; qu'il n'affecte que la chaîne qui lui suit
immédiatement. N'empèche que j'aurais fait que la précision
affecte les chaînes (comme dans printf), quitte à le rendre
volatile.

Et en passant, je dois ajouter qu'en fait, la distinction
volatile/persistant n'est qu'une convention, suivi de tous les
inserteurs et les extracteurs de la norme, mais à charge des
inserteurs et des extracteurs. Rien n'interdit d'écrire un
inserteur qui remet à zéro la précision, mais non la largueur,
par exemple. Malheureusement.

De toute façon, on a ce qu'on a dans ISO C++ et si on veut en
ajouter ou utiliser autre chose, it's easy enough :-)


Been there, done that:-).

À l'inverse, suppose que fixed et setprecision ne soient
pas persistants... (bah, ça ne serait pas si mal, si
c'était setp au lieu de setprecision :-)


Et qu'est-ce que ça changerait, s'ils n'était pas
persistants ? Tu précèdes normalement chaque champs par un
manipulateur quand même, qui précise comment le formatter
d'une manière sémantique (c-à-d qu'on dit que ses de
l'argent, ou un pourcentage, ou..., et qu'on définit une
fois dans le programme comment l'argent et les pourcentages
doivent être formattés).


J'ai l'habitude de tout spécifier à chaque bloc d'écriture,
mais pas à chaque valeur écrite. C'est un habitude qui va bien
avec la persistance de setprecision et fixed en particulier.


J'imagine que ça dépend beaucoup de ce qu'on fait. Dans la
pratique, je constate qu'il y a deux cas distinctes (et sans
doute plus, mais deux fréquents dans mon travail) : le texte
« normal » et les tableaux. Dans le texte normal, c'est rare
d'avoir plus d'un ou deux champs, et même alors, les différents
champs ont typiquement des sémantiques et des types
différents. Ce qui veut dire que la persistance ne me sert à
rien ; il faut tout spécifier à chaque champs. Dans les
tableaux, c'est un peu plus complexe, mais en général, ce sont
les colonnes qui détermine la sémantique et le type, alors qu'on
sort les données par ligne. Du coup, là aussi, il faut tout
spécifier à chaque champ.

J'imagine que dans les domaines où le calcul numérique est
important, il arrive qu'on sort des matrices, où et les colonnes
et les lignes ont tous le même type et la même sémantique. Dans
ce cas-là, c'est vrai que la persistance doit être bien
intéressante.

Par contre, à l'usage, je considère que setfill aurait
avantage à ne pas être persistant. En fait, pour faire plaisir
à tout le monde l'idéal aurait été d'avoir deux versions de
chacun des manipulateurs : une persistante, une non
persistante :

<< fixed << precision(2) << width(5) << fill('*') // non persistant
<< var1
<< setfixed << setp(2) << setw(5) << setfill('*') // persistant
<< var2 << var3

Il y aurait un problème avec cette approche ?


Je suis tout à fait de cet avis. D'autant plus qu'on a déjà deux
méthodes de positionner chaque champs : avec un fonction membre
de ios, et avec un manipulateur. Je le trouverais tout à fait
logique que les valeurs positionnées par fonctions membres
soient persistantes, et que celles positionnées par les
manipulateurs ne les soient pas.

L'implémentation, c'est moins évidente, mais je crois que c'est
jouable. Il faudrait évidemment un flag par valeur (et des
fonctions membres distinctes pour chaque champs dans setf) ; il
serait bien aussi que la rémise à zéro se fait dans le
destructeur de l'objet sentry, de façon à ce qu'on ne dépend pas
des inserteurs et des extracteurs (éventuellement écris par
l'utilisateur) d'implémenter cette logique un peu plus
compliquée.

--
James Kanze GABI Software
Conseils en informatique orientée objet/
Beratung in objektorientierter Datenverarbeitung
9 place Sémard, 78210 St.-Cyr-l'École, France, +33 (0)1 30 23 00 34




1 2