2010-08-29 36 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字节整数。