[英]How to convert float to byte array of length 4 (array of char*)?
如何將float轉換為長度為4的字節數組(char *的數組)? 我需要通過網絡發送一些數據,tcp,並需要將float作為字節數組發送。 (我知道兩位小數的精度,所以目前我在客戶端乘以100並在服務器上除以100 - 基本上轉換為整數然后用&0xff <<操作查找字節)。 但它很丑陋,可能會在一段時間內失去精確度。
將任何類型作為字節序列讀取非常簡單:
float f = 0.5f;
unsigned char const * p = reinterpret_cast<unsigned char const *>(&f);
for (std::size_t i = 0; i != sizeof(float); ++i)
{
std::printf("The byte #%zu is 0x%02X\n", i, p[i]);
}
從網絡流寫入浮點數的工作方式類似,只有你忽略了const
。
始終允許將任何對象重新解釋為一個字節序列(允許任何char
類型),這顯然不是別名違規。 請注意,任何類型的二進制表示當然都是依賴於平台的,因此如果收件人具有相同的平台,則只應將其用於序列化。
您要做的第一件事是確定網絡協議中浮動的格式。 只知道它是4個字節並不能說明多少:IBM大型機,Oracle Sparc和通常的PC都有四個字節的浮點數,但它們有三種不同的格式。 一旦您了解格式,根據它和您的可移植性要求,可以使用兩種不同的策略:
如果協議中的格式是IEEE(最常見的情況),並且您不必移植到非IEEE的機器(Windows和大多數Unix是IEEE大多數大型機不是),那么您可以使用類型punning將float轉換為uint32_t
,並使用以下任一方式輸出:
std::ostream&
output32BitUInt( std::ostream& dest, uint32_t value )
{
dest.put( (value >> 24) & 0xFF );
dest.put( (value >> 16) & 0xFF );
dest.put( (value >> 8) & 0xFF );
dest.put( (value ) & 0xFF );
}
對於big-endian(通常的網絡順序),或者:
std::ostream&
output32BitUInt( std::ostream& dest, uint32_t value )
{
dest.put( (value ) & 0xFF );
dest.put( (value >> 8) & 0xFF );
dest.put( (value >> 16) & 0xFF );
dest.put( (value >> 24) & 0xFF );
}
對於little-endian(由某些協議使用)。 您使用哪一個取決於為協議定義的格式。
要從float
轉換為uint32_t
,您必須檢查編譯器。 使用memcpy
是標准完全保證的唯一方法; 目的是在float上使用reinterpret_cast<uint32_t&>
,大多數(所有?)編譯器也支持使用union
。
如果您還需要移植到大型機,或者格式不是IEEE,那么您需要從浮點數中提取指數,符號和尾數,並以目標格式輸出每個。 像下面這樣的東西應該可以在任何機器上輸出IEEE big-endian(包括不使用IEEE的大型機),並且應該給你一些想法:
oxdrstream&
oxdrstream::operator<<(
float source )
{
BytePutter dest( *this ) ;
bool isNeg = source < 0 ;
if ( isNeg ) {
source = - source ;
}
int exp ;
if ( source == 0.0 ) {
exp = 0 ;
} else {
source = ldexp( frexp( source, &exp ), 24 ) ;
exp += 126 ;
}
uint32_t mant = source ;
dest.put( (isNeg ? 0x80 : 0x00) | exp >> 1 ) ;
dest.put( ((exp << 7) & 0x80) | ((mant >> 16) & 0x7F) ) ;
dest.put( mant >> 8 ) ;
dest.put( mant ) ;
return *this ;
}
( BytePutter
是一個簡單的類,負責處理通常的樣板並進行錯誤檢查。)當然,如果輸出格式不是IEEE,輸出的各種操作將會有所不同,但這應該顯示基本原理。 (如果你需要一些不支持uint32_t
的更具異國情調的大型機的可移植性,你可以用任何大於23位的無符號整數類型替換它。)
只需將數據疊加在一個區域中,即C中
union dataUnion {
float f;
char fBuff[sizeof(float)];
}
// to use:
dataUnion myUnion;
//
myUnion.f = 3.24;
for(int i=0;i<sizeof(float);i++)
fputc(myUnion.fbuff[i],fp); // or what ever stream output....
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.