2010-08-29 66 views
1

問題與變換字節數組漂浮/長用C

127 -1 -1 -1 -1 -1 -1 - 1

res應該是簽署的long的最大值,但是是-129。

編輯:這一個是照顧。這是通信問題的結果:對於提供data的人,long是八個字節;對於我的C它是四個。

浮子:

float *res; 
    /* ... */ 
    char float_num[4]; 
    for(i=0; i<4; i++) 
    float_num[i] = data[pos++]; 

    res = (float *)float_num; 

這是零。數組值:

62 -1 24 50

我還試圖memcpy(),但它產生零。我究竟做錯了什麼?


我的系統:Linux 2.6.31-16-generic i686 GNU/Linux

+0

哪個平臺,你的工作嗎?循環之前long_num []中的內容非常重要;數據[]中的內容至關重要。你可以使用:'char long_num [8] = {0x7F,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF};'你會更有說服力。與浮點示例類似。 – 2010-08-29 22:36:45

回答

2

這是兩個問題,非常無關。

在第一個,你的電腦是little-endian。符號位在long中設置,您拼在一起,因此結果爲負值。由於設置了許多「最高有效位」,因此接近於零。

在第二個示例中,不尊重strict aliasing rules可能是對怪異行爲的解釋。我不確定。如果您使用的是gcc,請嘗試使用聯合,gcc保證以這種方式使用聯合轉換數據時會發生什麼情況。

3

你是一個little-endian系統上運行的代碼。顛倒陣列中的字節順序並重試:

signed char long_num[] = {-1, -1, -1, -1, -1, -1, -1, 127}; 
// ... 
1

鑑於此代碼:

#include <stdio.h> 
#include <string.h> 

int main(void) 
{ 
    { 
     long res; 
     char long_num[8] = { 0x7F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF }; 
     memcpy(&res, long_num, 8); 
     printf("%ld = 0x%lX\n", res, res); 
    } 
    { 
     float res; 

     char float_num[4] = { 62, 0xFF, 24, 50 }; 
     memcpy(&res, float_num, 4); 
     printf("%f = %19.14e\n", res, res); 

    } 
    return 0; 
} 

在在MacOS X 10.6.4使用GCC 4.5.1 64位模式編譯給出:

-129 = 0xFFFFFFFFFFFFFF7F 
0.000000 = 8.90559981314709e-09 

這是一個little-endian的英特爾正確(好吧,'長'的價值是正確的)。

你想要做的是有點不尋常 - 不推薦。它不可移植,尤其是因爲存在端到端問題。

我以前寫的SPARC計算機上的一些相關的代碼(這是一個大端機):

union u_double 
{ 
    double dbl; 
    char data[sizeof(double)]; 
}; 

union u_float 
{ 
    float flt; 
    char data[sizeof(float)]; 
}; 

static void dump_float(union u_float f) 
{ 
    int exp; 
    long mant; 

    printf("32-bit float: sign: %d, ", (f.data[0] & 0x80) >> 7); 
    exp = ((f.data[0] & 0x7F) << 1) | ((f.data[1] & 0x80) >> 7); 
    printf("expt: %4d (unbiassed %5d), ", exp, exp - 127); 
    mant = ((((f.data[1] & 0x7F) << 8) | (f.data[2] & 0xFF)) << 8) | (f.data[3] & 0xFF); 
    printf("mant: %16ld (0x%06lX)\n", mant, mant); 
} 

static void dump_double(union u_double d) 
{ 
    int exp; 
    long long mant; 

    printf("64-bit float: sign: %d, ", (d.data[0] & 0x80) >> 7); 
    exp = ((d.data[0] & 0x7F) << 4) | ((d.data[1] & 0xF0) >> 4); 
    printf("expt: %4d (unbiassed %5d), ", exp, exp - 1023); 
    mant = ((((d.data[1] & 0x0F) << 8) | (d.data[2] & 0xFF)) << 8) | (d.data[3] & 0xFF); 
    mant = (mant << 32) | ((((((d.data[4] & 0xFF) << 8) | (d.data[5] & 0xFF)) << 8) | (d.data[6] & 0xFF)) << 8) | (d.data[7] & 0xFF); 
    printf("mant: %16lld (0x%013llX)\n", mant, mant); 
} 

static void print_value(double v) 
{ 
    union u_double d; 
    union u_float f; 

    f.flt = v; 
    d.dbl = v; 

    printf("SPARC: float/double of %g\n", v); 
    image_print(stdout, 0, f.data, sizeof(f.data)); 
    image_print(stdout, 0, d.data, sizeof(d.data)); 
    dump_float(f); 
    dump_double(d); 
} 


int main(void) 
{ 
    print_value(+1.0); 
    print_value(+2.0); 
    print_value(+3.0); 
    print_value(0.0); 
    print_value(-3.0); 
    print_value(+3.1415926535897932); 
    print_value(+1e126); 
    return(0); 
} 

這是我在這個平臺上得到。請注意,尾數中有一個隱含的'1'位,所以'3'的值只有一個位,因爲其他1位是隱含的。

SPARC: float/double of 1 
0x0000: 3F 80 00 00          ?... 
0x0000: 3F F0 00 00 00 00 00 00       ?....... 
32-bit float: sign: 0, expt: 127 (unbiassed  0), mant:    0 (0x000000) 
64-bit float: sign: 0, expt: 1023 (unbiassed  0), mant:    0 (0x0000000000000) 
SPARC: float/double of 2 
0x0000: 40 00 00 00          @... 
0x0000: 40 00 00 00 00 00 00 00       @....... 
32-bit float: sign: 0, expt: 128 (unbiassed  1), mant:    0 (0x000000) 
64-bit float: sign: 0, expt: 1024 (unbiassed  1), mant:    0 (0x0000000000000) 
SPARC: float/double of 3 
0x0000: 40 40 00 00          @@.. 
0x0000: 40 08 00 00 00 00 00 00       @....... 
32-bit float: sign: 0, expt: 128 (unbiassed  1), mant:   4194304 (0x400000) 
64-bit float: sign: 0, expt: 1024 (unbiassed  1), mant: 2251799813685248 (0x8000000000000) 
SPARC: float/double of 0 
0x0000: 00 00 00 00          .... 
0x0000: 00 00 00 00 00 00 00 00       ........ 
32-bit float: sign: 0, expt: 0 (unbiassed -127), mant:    0 (0x000000) 
64-bit float: sign: 0, expt: 0 (unbiassed -1023), mant:    0 (0x0000000000000) 
SPARC: float/double of -3 
0x0000: C0 40 00 00          [email protected] 
0x0000: C0 08 00 00 00 00 00 00       ........ 
32-bit float: sign: 1, expt: 128 (unbiassed  1), mant:   4194304 (0x400000) 
64-bit float: sign: 1, expt: 1024 (unbiassed  1), mant: 2251799813685248 (0x8000000000000) 
SPARC: float/double of 3.14159 
0x0000: 40 49 0F DB          @I.. 
0x0000: 40 09 21 FB 54 44 2D 18       @.!.TD-. 
32-bit float: sign: 0, expt: 128 (unbiassed  1), mant:   4788187 (0x490FDB) 
64-bit float: sign: 0, expt: 1024 (unbiassed  1), mant: 2570638124657944 (0x921FB54442D18) 
SPARC: float/double of 1e+126 
0x0000: 7F 80 00 00          .... 
0x0000: 5A 17 A2 EC C4 14 A0 3F       Z......? 
32-bit float: sign: 0, expt: 255 (unbiassed 128), mant:    0 (0x000000) 
64-bit float: sign: 0, expt: 1441 (unbiassed 418), mant:  -1005281217 (0xFFFFFFFFC414A03F) 

你必須做一些diddling的代碼,使之成爲小端機器上三立工作就像英特爾的機器。

0

如果您正在通信的不同機器之間的網絡(如更新暗示),你必須確定你的協議,以確保兩端知道如何準確地獲取數據到另一端。這不一定是微不足道的 - 世界上有許多複雜的系統。

  • 一個標準的方法是爲字節定義一個規範的排序 - 以及這些類型的規範大小。例如,在處理IPv4地址時,這通常稱爲「網絡字節順序」。它部分地定義了數據的字節順序;它也是關於限定的值被髮送作爲一個4字節的值,而不是作爲一個8字節值 - 或反之亦然。

  • 的另一種技術是基於ASN.1 - ,其與類型,長度和值(TLV編碼)對數據進行編碼。每一位數據都會發送一些信息,用於識別正在發送的內容。

  • 由IBM DB2數據庫管理系統所使用的協議DRDA具有不同的策略 - 「接收機使得右」。發送者在會話開始時識別他們是什麼類型的機器,然後以他們自己最方便的格式發送數據。接收者負責確定發送的內容。 (這適用於數據庫服務器和數據庫客戶端;客戶端以其首選符號發送,服務器修復接收的內容,而服務器以其首選符號發送,而客戶端修復其收到的內容。)

  • 處理這些問題的另一個非常有效的方法是使用文本協議。數據作爲數據的文本版本進行傳輸,並具有用於識別不同字段的清晰機制。這比各種二進制編碼機制更容易調試,因爲您可以轉儲數據並查看發生了什麼。這不是比二進制協議效率一定要少得多 - 特別是如果你通常發送實際包含個位數的整數值的8字節整數。