2016-01-27 1 views
0

J'ai le morceau de code suivant:Existe-t-il une meilleure option que reinterpret_cast <char*> lors de la lecture de std :: istream?

std::istream is; 
// ... stream initialization ... 
while(is) 
{ 
    uint32_t next4Bytes = 0; 
    is.read(reinterpret_cast<char*>(&next4Bytes), 4); 
    if(next4Bytes == 218893066) 
    { 
    is.seekg(-4, std::ios_base::cur); 
    break; 
    } 
    else 
    is.seekg(-3, std::ios_base::cur); 
} 

Y at-il d'autres mieux que reinterpret_cast<char*> à lire 4 octets de std::istream dans un uint32_t? (évidemment autre que la fonte de style c)

+0

Vous pouvez faire 'union fourBytes {uint32_t integer; char chars [4];} '(Je sais que c'est un comportement indéfini). Je ne sais pas si c'est "mieux" mais c'est différent, donc c'est ça. – PeterT

+0

'char * readBuf; uint32_t next4Bytes; est.read (readBuf, 4); memcpy (& next4Bytes, readBuf, 4); 'ceci sans aucun typage – Balu

+0

Dans mon opinion personnelle: Pensez à écrire votre propre fonction wrapper' toCharPtr' (ou similaire). La conversion en 'char *' est très courante, légale, ** et nécessaire ** dans le code IO, de sorte que je ne vois aucune raison d'encombrer mon code avec ces distributions de réinterprétation (que je traite comme un grand point d'exclamation dans la plupart des autres circonstances) – MikeMB

Répondre

7

Je ne pense pas qu'il y en ait, et je ne pense pas que vous en ayez besoin. Vous prenez quatre octets et les réinterprétez; reinterpret_cast décrit précisément votre intention.

1

Vous pouvez utiliser cast de style C, en fait la même chose, mais plus court pour écrire

is.read((char*)&next4Bytes, 4); 
+0

Je voudrais upvote, mais l'OP explicitement exclut les lancers de style c. – MikeMB

+0

Ups, ne l'a pas vu. Ma faute – Jeka

5

Vous pouvez envelopper CAST dans une fonction de lecteur basé sur un modèle bien:

template<typename T> 
std::streamsize read(T* out, std::istream& stream, size_t count=1) { 
    stream.read(reinterpret_cast<char*>(out), sizeof(T)*count); 
    return stream.gcount(); 
} 

Si vous ne Ne vous souciez pas de lire les tableaux, vous pouvez même omettre l'argument count et le rendre encore plus simple. Il y a des façons de modifier cela à vos propres besoins. Au lieu de retourner simplement gcount, vous pouvez le diviser par sizeof (T) si vous êtes intéressé par le nombre de valeurs réellement lues, au lieu de combien d'octets ont été lus. (Ceci est très similaire à la façon dont la valeur de retour de fread fonctionne). Ou vous pouvez lancer une exception si toutes les données ne peuvent pas être lues.

+1

Pour les compilateurs compatibles C++ 11, j'aime ajouter static_assert (std :: is_trivially_copyable :: value, "Ne peut pas être utilisé sur des types non-trivialement copiables)." De cette façon, le compilateur peut rejeter une tentative d'utilisation Fonctionne sur des types plus compliqués, tels que 'std :: string'. –

+0

Je suis d'accord, c'est un bon ajout! –

0

L'idée est que read lit des octets, par opposition à l'opérateur >>, qui est une construction de haut niveau.

Vous lisez les octets soit à char ou unsigned char, parce que c'est ce que les octets sont tous. Essayer de contourner cela à peu près annule le but de read qui est de lire les octets. Donc, si ce qui vous dérange est la verbosité de reinterpret_cast, utilisez des modèles. Si ce qui vous dérange, c'est que vous devez lire des octets dans un entier, essayez de stocker l'entier sous forme de chaîne en premier lieu et extrayez-le avec l'opérateur >> approprié.