OVH Cloud OVH Cloud

fonction template et ostream

30 réponses
Avatar
Alain Cabiran
bonjour,

j'ai un petit problème :

template<class A> std::ostream write(std::ostream & s, const A & valeur)
{
1) s.write(static_cast<const char *>(&valeur), sizeof(A));

ou

2) s.write(&valeur, sizeof(A));


return s;
}

ne fonctionnent pas. Quelqu'un a une idée de ce que je dois mettre
pour écrire un type quelconque en binaire ?

merci d'avance pour toute piste

Alain C.

10 réponses

1 2 3
Avatar
Fabien LE LEZ
On Tue, 04 Oct 2005 15:05:01 +0200, Alain Cabiran
:

[46 lignes de citation]



T'es sûr de ne pas vouloir aussi citer l'intégralité des messages
parus ici en 2005 ?

:-(

J'en suis arrivé à la même conclusion : les données stockées ne seront
pas portables d'une plateforme à une autre.


Même pas d'une version à l'autre de ton compilo, en fait.

Tiens, une question subsidiaire :

Imaginons un compilateur qui stocke un booléen dans un octet, en
prenant comme valeur le n-ième bit, n étant choisi entre 0 et 7 au
démarrage du programme. En d'autres termes, la représentation binaire
d'un bool varie à chaque démarrage.
Un tel compilo serait-il conforme ?

j'en suis malheureusement
arrivé à utiliser le stockage binaire parce que je n'ai pas trouvé
comment stocker et relire 2 chaines de caractères consécutives de façon
simple avec iostream en "mode texte".


Quid du lien que je t'ai donné ?


Avatar
Alain Cabiran
T'es sûr de ne pas vouloir aussi citer l'intégralité des messages
parus ici en 2005 ?

:-(


non :) bon ok je coupe quand c'est plus utile

J'en suis arrivé à la même conclusion : les données stockées ne seront
pas portables d'une plateforme à une autre.
Même pas d'une version à l'autre de ton compilo, en fait.



arggh !! donc va falloir que je trouve autre chose...
J'en arrive à me demander comment les programmes c++
stockent les données sur disque !

Tiens, une question subsidiaire :

Imaginons un compilateur qui stocke un booléen dans un octet, en
prenant comme valeur le n-ième bit, n étant choisi entre 0 et 7 au
démarrage du programme. En d'autres termes, la représentation binaire
d'un bool varie à chaque démarrage.
Un tel compilo serait-il conforme ?


un spécialiste du c++ pourrait mieux répondre que moi mais
si je me rappelle bien ce que j'ai lu dans le bouquin de stroustrup
un bool est true quand il n'est pas à 0 donc à priori je dirais oui.

Quid du lien que je t'ai donné ?


ça à l'air pas mal quoique complexe en regard des operateurs << et >>
ou même du système utilisé par Qt.
J'essaierai de toute façon, j'apprend, donc j'ai tout à gagner.

Alain C.


Avatar
Bertrand Lenoir-Welter
Alain Cabiran wrote:

J'en arrive à me demander comment les programmes c++
stockent les données sur disque !


En enfilant des octets. A l'appli de voir ensuite ce qu'elle en fait. Et
ça, ça regarde pas trop le compilo.

Avatar
Alain Cabiran
Alain Cabiran wrote:

J'en arrive à me demander comment les programmes c++
stockent les données sur disque !


En enfilant des octets. A l'appli de voir ensuite ce qu'elle en fait. Et
ça, ça regarde pas trop le compilo.


très drôle, vraiment.

j'ai touché pendant pas mal de temps à turbo pascal puis à delphi
puis j'ai abordé le c++ façon grouik avec qt, pas de template
pas de stl, pas de multi-héritage. J'ai jamais eu de difficultés
à trouver comment stocker une structure ou une instance de classe
puis la relire.

ensuite j'ai commencé à lire le forum et j'ai acheté le bouquin
de stroustrup et celui de josuttis pour passer d'une utilisation
purement qt du c++ à une utilisation plus proche de ce qu'il est
réellement : la librairie du c++ dont la stl fait partie.

depuis, le stockage des données est ma bête noire. il n'y a rien
du tout à part de quoi écrire et de quoi lire des fichiers textes.
or iostream ne sait pas parser 2 chaines qui se suivent mais
deux "mots" (s*ws+w en perl sauf erreur de ma part).

que puis-je, en néophyte du c++ sans toolkit, en déduire ?
que les programmeurs c++ utilisent systématiquement des toolkits
extérieurs ? qu'il ne stockent que des fichiers textes ?
troll{que le c++ c'est comme le java, ça sert à rien ?} :)
je n'y crois pas une seconde, d'où mon interrogation :

comment, ie quel sont les moyens mis en oeuvre, par les programmeurs
qui lisent ce forum, pour stocker leurs données sur disque ?

cordialement

Alain C.


Avatar
Jean-Marc Bourguet
Alain Cabiran writes:

comment, ie quel sont les moyens mis en oeuvre, par les programmeurs
qui lisent ce forum, pour stocker leurs données sur disque ?


Je ne m'occupe pas de ca personnellement, mais les gens qui le font
chez nous font des fichiers qui sont lisibles sur l'ensemble de nos
plateformes (petit et grand boutiens, 32 et 64 bits) et on a de la
compatibilite dans les deux sens pour autant qu'on n'utilise pas de
nouveaux objets.

A priori un format binaire a ete defini et est parse byte par byte
(vraissemblablement octet par octet, on ne supporte pas des machines
bizarre de ce point de vue) et son extensibilite est prevue d'une
maniere un peu meilleure que simplement avec un numero de version
(mais je ne connais pas les details).

C'est d'ailleur la seule maniere (definir un format en prevoyant des
possibilites d'evolution, puis le parser; le format ne doit pas etre
forcement binaire) qui est robuste et a l'epreuve du temps. C'est pas
tres complique, il faut juste etre prevoyant (autrement dit s'etre
plante une ou deux fois avant ou etre capable de recuperer
l'experience de ceux qui sont deja passe par la).

Parser, c'est pas complique non plus. Il faut juste ne pas couper les
coins et supposer que le fichier est correct a priori.

A+

--
Jean-Marc
FAQ de fclc++: http://www.cmla.ens-cachan.fr/~dosreis/C++/FAQ
C++ FAQ Lite en VF: http://www.ifrance.com/jlecomte/c++/c++-faq-lite/index.html
Site de usenet-fr: http://www.usenet-fr.news.eu.org

Avatar
Bertrand Lenoir-Welter
Alain Cabiran wrote:

En enfilant des octets. A l'appli de voir ensuite ce qu'elle en fait. Et
ça, ça regarde pas trop le compilo.


très drôle, vraiment.


C'était pas une plaisanterie. A partir du moment où tu peux écrire/lire
un octet dans un fichier, le reste n'est plus que de la broderie. J'ai
des programmes qui manipulent des fichiers de données binaires avec
entiers 8, 16 & 32 bits et chaînes de caractères mélangés, ainsi que des
fichiers textes, et je vois pas où est le blème.

Avantage certain : le compilo, la version du programme, la taille
élastique des enregsitrements, etc., on s'en fout. La seule chose qui
pourrait encore varier, c'est le codage Little/Big Endian ou le format
des caractères. Rien de bien méchant.

Maintenant, si tu veux avoir un truc qui enregistre tout seul une
structure ou une classe sur disque, je sais pas ; j'ai jamais été
chercher ça en C. Si j'ai besoin d'enregistrer un type structuré,
j'enregistre tout simplement ses composants un par un en binaire à
grands renforts d'unions et de castings.


j'ai touché pendant pas mal de temps à turbo pascal puis à delphi


Ouais, Turbo-Pascal permettait de définir un type structuré et un
fichier d'enregistrements de ce type pour l'envoyer direct sur disque.
Vieux souvenir... Oublie tout ça et bienvenue dans le C. C'est pas si
pénible à gérer, tu verras.


Avatar
Fabien LE LEZ
On Tue, 04 Oct 2005 18:06:40 +0200, Alain Cabiran
:

que les programmeurs c++ utilisent systématiquement des toolkits
extérieurs ?


Je ne suis pas sûr de comprendre ta question, mais le langage C++ tout
seul ne sert strictement à rien.
Avec l'acces à l'API de l'OS, c'est déjà plus utilisable.
Et quand on rajoute les bibliothèques dont on a besoin, on peut
commencer à programmer sérieusement.

qu'il ne stockent que des fichiers textes ?


À part pour la vidéo et le son, je n'utilise effectivement que des
formats lisibles par un humain. Du texte formaté sera enregistré en
RTF ou HTLM ; des paramètres seront enregistrés sous la forme

nom= valeur

etc.

Généralement, j'enregistre avec l'opérateur << , et je lis avec
getline et un parser sur mesure.

J'avoue n'avoir jamais utilisé le système de sérialisation de Boost,
mais à première vue il a l'air très simple : il suffit, pour chaque
classe, de créer une fonction qui énumère les variables à enregistrer.

Avatar
kanze
Jean-Marc Bourguet wrote:
Alain Cabiran writes:

comment, ie quel sont les moyens mis en oeuvre, par les
programmeurs qui lisent ce forum, pour stocker leurs données
sur disque ?


Je ne m'occupe pas de ca personnellement, mais les gens qui le
font chez nous font des fichiers qui sont lisibles sur
l'ensemble de nos plateformes (petit et grand boutiens, 32 et
64 bits) et on a de la compatibilite dans les deux sens pour
autant qu'on n'utilise pas de nouveaux objets.


J'ai déjà écrit pas mal de logiciels qui communiquaient avec
d'autres processeurs. Dont je n'en connaissais même pas le
format interne des données, parfois. C'est même possible qu'il y
a eu des Unisys 2200 (36 bits, complément à 1) dans le reseau;
il y a certainement eu des IBM 390 (virgule flottant à base 16,
EBCDIC à la place d'ASCII).

C'est le même problème. On définissait un format (ou on en
prenait un existant), et on y conformait (ce qui était plus
difficile pour les machines un peu exotiques, mais c'était leur
problème, pas le mien:-)).

A priori un format binaire a ete defini et est parse byte par
byte (vraissemblablement octet par octet, on ne supporte pas
des machines bizarre de ce point de vue) et son extensibilite
est prevue d'une maniere un peu meilleure que simplement avec
un numero de version (mais je ne connais pas les details).


Si tu veux voir jusqu'à quel extrème on peut aller en matière de
souplesse et de portabilité, régarde la définition de l'encodage
BER d'un ASN.1 float. (Le but ici, c'est que quand deux machines
qui ont le même format se communiquent, c'est ultra-simple. Ce
qui rend les autres cas extrèmement complexe.)

C'est d'ailleur la seule maniere (definir un format en
prevoyant des possibilites d'evolution, puis le parser; le
format ne doit pas etre forcement binaire) qui est robuste et
a l'epreuve du temps. C'est pas tres complique, il faut juste
etre prevoyant (autrement dit s'etre plante une ou deux fois
avant ou etre capable de recuperer l'experience de ceux qui
sont deja passe par la).


D'autres y sont déjà passé par là. Tant que faire, utiliser un
format existant déjà éprouvé, du genre BER ou XDR.

Parser, c'est pas complique non plus. Il faut juste ne pas
couper les coins et supposer que le fichier est correct a
priori.


Parser, ce n'est pas compliqué, dépend du format et du hardware
supporté. Dans beaucoup de cas, on a pû écarter les flottants,
et se limiter à des machines complément à deux pour les entiers.
Alors, c'est vraiment simple -- comme tu dis, le seul problème
(et c'est un problème très mineur), c'est la détection des
erreurs. Si tu dois supporter des machines non complément à
deux, l'encodage ou le décodage des entiers devient beaucoup
plus ardu. Et quant aux flottants... (Mais les machines Unix
courantes ainsi que les machines Windows utilisent tous le
format IEEE. Il suffit donc d'utiliser l'image comme une suite
d'octets, dans un ordre prédéfini, si ça suffit comme
portabilité.)

--
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
Jean-Marc Bourguet
"kanze" writes:

(Mais les machines Unix courantes ainsi que les machines Windows
utilisent tous le format IEEE. Il suffit donc d'utiliser l'image
comme une suite d'octets, dans un ordre prédéfini, si ça suffit
comme portabilité.)


J'avais en tete (Gaby doit pouvoir confirmer) qu'une simple
reorganisation des octets ne suffit pas toujours.

A+

--
Jean-Marc
FAQ de fclc++: http://www.cmla.ens-cachan.fr/~dosreis/C++/FAQ
C++ FAQ Lite en VF: http://www.ifrance.com/jlecomte/c++/c++-faq-lite/index.html
Site de usenet-fr: http://www.usenet-fr.news.eu.org

Avatar
kanze
Alain Cabiran wrote:

[...]
J'en suis arrivé à la même conclusion : les données stockées
ne seront pas portables d'une plateforme à une autre.


Ni d'une version du compilateur à une autre, ni entre des
compilations avec des options différentes.

j'en suis malheureusement arrivé à utiliser le stockage
binaire parce que je n'ai pas trouvé comment stocker et relire
2 chaines de caractères consécutives de façon simple avec
iostream en "mode texte".

exemple :

1 5 chaine n°1 45 chaine 2 3 1 c1 5 d, e 3 f
codé en réalité comme ceci :
1 5 "chaine n°1" 45 "chaine 2" 2 3 1 "c1" 5 "d, e" 3 "f"

j'ai mis des guillemets juste pour séparer les chaines. mais
du fait qu'elles n'ont pas de contraintes de caractères, je ne
vois pas quoi utiliser comme séparateur...


Il y a plusieurs solutions: une solution simple consiste à
préfixer la chaîne par sa longueur, soi sur un nombre de
chiffres fixe, soit avec un séparateur pour le cas où la chaîne
commence par un chiffre. Donc, si on fait longueur ':' chaîne,
le code pour lire une chaîne serait :

std::istream&
operator>>( std::istream& source, ExternalString const& dest )
{
size_t l ;
source >> l >> separ( ':' ) ;
std::vector< char > ch( l ) ;
source.read( &ch[ 0 ], l ) ;
if ( source ) {
dest.setValue( std::string( ch.begin(), ch.end() ) ) ;
}
return source ;
}

ExternalString est une simple classe qui wrappe une référence à
une chaîne.

Sinon, j'ai une classe ParsableString qui assure
l'aller/retour ; si la chaîne contient des caractères
non-alphanumérique, il est sortie entre guillemets, avec des
échappements à la C pour des méta-caractères ('"', '' et tout
ce qui n'est pas imprimable, genre 't'... le cas échéant, il
utiliser 'xnn'). C'est nettement plus complexe que la fonction
ci-dessus, mais le résultat est beaucoup plus facile à lire (et
à éditer) par une personne. De l'en-tête :

// ParsableString :
// ----------------
//
// Un wrapper pour une chaîne, qui sert au formattage des
// entrées/sorties, de façon que les chaînes écrites peuvent
être
// rélues de façon sûre et qu'elles peuvent contenir n'importe
// quel caractère.
//
// Comme c'est le cas pour char const* et std::string << lit des
// mots, et >> les écrit. Ce qui diffère, c'est la définition
de
// « mot ». Un mot est soit un ou plusieurs caractères pris
dans
// l'ensemble [:alpha:]|[:digit:]|_ (selon le locale global C),
// soit une séquence délimitée par '"' ou par ''', qui
serait
// terminée par le délimiteur correspondant. Une séquence ainsi
// délimitée peut aussi contenir des séquences échappement ;
// toutes les séquences classiques de C/C++ sont permises. (En
// revanche, des fins de lignes non échappées ne sont pas
// permises)

j'ai jeté un coup d'oeil à qt, gtk, wxwindows, mysql, gdbm
mais en suis revenu, beaucoup de boulot pour un si petit
programme, je me suis rabattu vers ncurses, simple et
suffisant pour l'instant. "Malheureusement" contrairement aux
autres libs citées, la gestion des entrées/sorties disque se
fait par la stl qui ne propose rien de portable.


Le problème, c'est qu'il y a tellement de formats possibles. Si
tu veux vraiment du binaire, par exemple, il doit exister des
flux XDR quelque part, voire même des flux ASN.1/BER. Si c'est
pour une utilisation purement interne, en revanche, j'aurais
tendance à préférer un format maison pûrement ASCII -- la mise
au point du programme se trouve largement simplifiée si on peut
lire les fichiers intermédiaire sans outil spécial.

--
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 3