Vous devez définir un format, et le mettre en œuvre. Typiquement, la plupart des protocoles réseau que je connais utilisent les flottants et les doubles IEEE, la sortie big-endian (mais d'autres formats sont possibles). L'avantage d'utiliser les formats IEEE est que c'est ce qu'utilisent la plupart des machines actuelles de tous les jours internes ; si vous êtes sur l'une de ces machines (et que la portabilité de votre code vers d'autres machines, comme les mainframes, n'est pas un problème), vous pouvez vous "convertir" au format simplement en effectuant une conversion de type vers un int non signé de la de la même taille, et en le sortant. Ainsi, par exemple, vous pourriez avoir :
obstream&
operator<<( obstream& dest, uint64_t value )
{
dest.put((value >> 56) & 0xFF);
dest.put((value >> 48) & 0xFF);
dest.put((value >> 40) & 0xFF);
dest.put((value >> 32) & 0xFF);
dest.put((value >> 24) & 0xFF);
dest.put((value >> 16) & 0xFF);
dest.put((value >> 8) & 0xFF);
dest.put((value ) & 0xFF);
return dest;
}
obstream&
operator<<( obstream& dest, double value )
{
return dest << reinterpret_cast<uint64_t const&>( value );
}
Si vous devez être portable sur une machine ne supportant pas IEEE (par exemple, l'un des les mainframes modernes), vous aurez besoin de quelque chose d'un peu plus compliqué :
obstream&
obstream::operator<<( obstream& dest, double value )
{
bool isNeg = value < 0;
if ( isNeg ) {
value = - value;
}
int exp;
if ( value == 0.0 ) {
exp = 0;
} else {
value = ldexp( frexp( value, &exp ), 53 );
exp += 1022;
}
uint64_t mant = static_cast< uint64_t >( value );
dest.put( (isNeg ? 0x80 : 0x00) | exp >> 4 );
dest.put( ((exp << 4) & 0xF0) | ((mant >> 48) & 0x0F) );
dest.put( mant >> 40 );
dest.put( mant >> 32 );
dest.put( mant >> 24 );
dest.put( mant >> 16 );
dest.put( mant >> 8 );
dest.put( mant );
return dest;
}
(Notez que cela ne gère pas correctement les NaN et les infinis. Personnellement, je les bannirais du format, car toutes les représentations en virgule flottante ne conviennent pas. pas toutes les représentations en virgule flottante les supportent. Mais alors, il n'y a pas de format en virgule flottante flottante sur un mainframe IBM qui supportera 1E306, bien que vous pouvez l'encoder dans le format double IEEE ci-dessus).
La lecture est, bien sûr, le contraire. Soit :
ibstream&
operator>>( ibstream& source, uint64_t& results )
{
uint64_t value = (source.get() & 0xFF) << 56;
value |= (source.get() & 0xFF) << 48;
value |= (source.get() & 0xFF) << 40;
value |= (source.get() & 0xFF) << 32;
value |= (source.get() & 0xFF) << 24;
value |= (source.get() & 0xFF) << 16;
value |= (source.get() & 0xFF) << 8;
value |= (source.get() & 0xFF) ;
if ( source )
results = value;
return source;
}
ibstream&
operator>>( ibstream& source, double& results)
{
uint64_t tmp;
source >> tmp;
if ( source )
results = reinterpret_cast<double const&>( tmp );
return source;
}
ou si vous ne pouvez pas compter sur l'IEEE :
ibstream&
ibstream::operator>>( ibstream& source, double& results )
{
uint64_t tmp;
source >> tmp;
if ( source ) {
double f = 0.0;
if ( (tmp & 0x7FFFFFFFFFFFFFFF) != 0 ) {
f = ldexp( ((tmp & 0x000FFFFFFFFFFFFF) | 0x0010000000000000),
static_cast<int>( (tmp & 0x7FF0000000000000) >> 52 )
- 1022 - 53 );
}
if ( (tmp & 0x8000000000000000) != 0 ) {
f = -f;
}
dest = f;
}
return source;
}
(Cela suppose que l'entrée n'est pas un NaN ou un infini).