簡體   English   中英

如何將float轉換為長度為4的字節數組(char *的數組)?

[英]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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM