Twitter iPhone pliant OnePlus 11 PS5 Disney+ Orange Livebox Windows 11

lecture trame binaires

1 réponse
Avatar
JBB
Pour stocker mes trames binaires j'utilise finalement un std::string
Maintenant quand je veux lire par exemple un entier dan ma trame j'ai une methode:
lireEntier(std::string)

et plutôt que de lui passer ma string je lui passe un iterator par référence

int lireEntier(std::string::iterator & it)

comme ça je peux appeler lireEntier plusieurs fois de suite

et même
int lireEntier(std::string::const_iterator & it) car la lecture n'altère pas ma trame.
sa ressemble du coup à ce que je faisais avant en C
int lireEntier(const char * & pdata)


du coup j'au une méthode du gnre

traiterTram(const std::string & trame) {

std::string::iterator it = trame.begin();
int n1 = lireEntier(it);
int n2 = lireEntier(it);
if ( it == trame.end()) { //trame de la bonne taille
//traiter n1 et n2
}
else if ( it > trame.end()) { //trame trop courte
}else { //trame trop longue
}

je me pose des question quant à savoir si it peut être > à end ?
est bien raisonnable de déréférencer un iterator au delà de end? ( exception?)
Pour éviter cela est ce que je peux faire des tests du genre:
int lireEntier32(std::string::iterator & it,std::string::iterator end) {
if (it + 4 >= end) //probleme


Qu'est ce que vous pensez de tout ça?
N'y a t'il pas une librairie standart(?) qui fait ça?

Merci,

1 réponse

Avatar
James Kanze
On Mar 29, 10:58 am, JBB wrote:
Pour stocker mes trames binaires j'utilise finalement un std::string


Je lui aurais probablement préférer std::vector<>, mais qu'importe.

Maintenant quand je veux lire par exemple un entier dan ma
trame j'ai une methode:
lireEntier(std::string)

et plutôt que de lui passer ma string je lui passe un iterator par ré férence

int lireEntier(std::string::iterator & it)

comme ça je peux appeler lireEntier plusieurs fois de suite

et même
int lireEntier(std::string::const_iterator & it)
car la lecture n'altère pas ma trame.


J'en fais autant assez souvent. Seulement... l'idiome de la STL
exige deux itérateurs, afin de savoir où s'arrêter. Alors, ou
bien, tu en crées une classe pour l'encapsuler (voir ma classe
ParserSource à
http://kanze.james.neuf.fr/doc/en/Text/html/index.html, ou...
std::streambuf, surtout si tu as les octets dans un string),
soit tu passes aussi un itérateur de fin à la fonction, soit (là
aussi, parce que c'est un std::string ou un std::vector) tu
exiges que l'utilisateur fasse la vérification avant, avec
quelque chose du genre :
if ( std::distance( s.begin(), s.end() ) != N ) {
// Erreur de taille du bloc...
}

Le plus idiomatique, c'est probablement :
int lireEntier( std::string::const_iterator& current,
std::string::const_iterator end ) ;
sauf que déjà, passer un itérateur par référence, ce n'est pas
vraiment idiomatique.

(Une autre solution qui me sert dans un cas bien précis, c'est
d'utiliser deux fonctions :

template< typename FwdIter >
int getValue( FwdIter begin, FwdIter end ) ;

template< typename FwdIter >
FwdIter next( FwdIter begin, FwdIter end ) ;

Ça marche bien dans mon cas précis parce que c'est le contenu de
l'octet sous begin qui détermine la longueur. Je ne suis pas sûr
que ce soit une bonne idée autrement.)

sa ressemble du coup à ce que je faisais avant en C
int lireEntier(const char * & pdata)


Sauf que là aussi, tu avais le problème de savoir quand tu
débordais.

du coup j'au une méthode du gnre

traiterTram(const std::string & trame) {

std::string::iterator it = trame.begin();
int n1 = lireEntier(it);
int n2 = lireEntier(it);
if ( it == trame.end()) { //trame de la bonne taille
//traiter n1 et n2}

else if ( it > trame.end()) { //trame trop courte

}else { //trame trop longue
}

je me pose des question quant à savoir si it peut être > à end ?


En effet, il n'y a pas d'opérateur < ni > défini pour les
itérateurs. Et qu'incrémenter au delà de la fin donne un
comportement indéfini -- des versions récentes de g++ ou de
VC++ garantissent un crash immédiate, mais avec la plupart des
implémentations, c'est vraiment n'importe quoi.

est bien raisonnable de déréférencer un iterator au delà de
end? ( exception?)


Comportement indéfini. Ne le fait surtout pas.

Pour éviter cela est ce que je peux faire des tests du genre:
int lireEntier32(std::string::iterator & it,std::string::iterator end) {
if (it + 4 >= end) //probleme


Il n'y a pas de >= non plus. Ce que tu peux faire, c'est :

if ( end - it < 4 ) // problème...
sinon :
if ( std::distance( it, end ) < 4 ) // ...

Ce dernier a l'avantage de marcher quelque soit le type
d'itérateur (sauf qu'avec un InputIterator, tu auras lu les
valeurs dans distance).

Qu'est ce que vous pensez de tout ça?


C'est un bon début, mais il faut bien reflechier sur comment tu
veux valider l'accès avant de déréférener l'itérateur, et du
coup, comment tu veux rapporter une erreur. (J'ai dû étendre
Fallible pour ça, dans un cas -- le simple fait qu'il y a eu
une erreur ne suffisait pas ; il fallait aussi un code
d'erreur.)

N'y a t'il pas une librairie standart(?) qui fait ça?


Standard, non (sauf que dans la mesure où stringbuf ou
istringstream ferait ton affaire). J'ai un [io]xdrstream en
cours, mais j'ai tellement d'autres choses plus pressantes, ce
n'est pas sûr qu'il soit jamais fini. (Et évidemment, elle ne
sera jamais standard.)

--
James Kanze (GABI Software) email:
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