如何获取浮点字节?

mFe*_*ein 7 c floating-point

我正在使用HIDAPI将一些数据发送到USB设备.这个数据只能作为字节数组发送,我需要在这个数据数组中发送一些浮点数.我知道浮点数有4个字节所以我认为这可能有用:

float f = 0.6;
char data[4];

data[0] = (int) f >> 24;
data[1] = (int) f >> 16;
data[2] = (int) f >> 8;
data[3] = (int) f;
Run Code Online (Sandbox Code Playgroud)

后来我所要做的就是:

g = (float)((data[0] << 24) | (data[1] << 16) | (data[2] << 8) | (data[3]) );
Run Code Online (Sandbox Code Playgroud)

但测试这一点告诉我,像float返回的线总是4.我的代码出了什么问题,我怎么能正确地做到这一点(即在4个字节字节中打破浮点内部数据并在以后重建同一个浮点数)?

编辑:

我能够用以下代码完成此任务:

float f = 0.1;
unsigned char *pc;
pc = (unsigned char*)&f;

// 0.6 in float
pc[0] = 0x9A;
pc[1] = 0x99;
pc[2] = 0x19;
pc[3] = 0x3F;

std::cout << f << std::endl; // will print 0.6
Run Code Online (Sandbox Code Playgroud)

*(unsigned int*)&f = (0x3F << 24) | (0x19 << 16) | (0x99 << 8) | (0x9A << 0);
Run Code Online (Sandbox Code Playgroud)

我知道memcpy()是一种"更清洁"的方式,但这种方式我认为性能稍好一些.

Ker*_* SB 19

你可以这样做:

char data[sizeof(float)];


float f = 0.6f;

memcpy(data, &f, sizeof f);    // send data


float g;

memcpy(&g, data, sizeof g);    // receive data
Run Code Online (Sandbox Code Playgroud)

为了使其工作,两台机器都需要使用相同的浮点表示.


正如评论中正确指出的那样,你不一定需要做额外的事情memcpy; 相反,您可以f 直接将其视为一个字符数组(任何签名).但是,你仍然必须memcpy在接收方做,因为你可能不会将任意数组的字符视为浮点数!例:

unsigned char const * const p = (unsigned char const *)&f;
for (size_t i = 0; i != sizeof f; ++i)
{
    printf("Byte %zu is %02X\n", i, p[i]);
    send_over_network(p[i]);
}
Run Code Online (Sandbox Code Playgroud)


pab*_*977 8

在标准C中,保证任何类型都可以作为字节数组进行访问.当然,直接的方法是使用工会:

 #include <stdio.h> 

 int main(void)
 {
    float x = 0x1.0p-3; /* 2^(-3) in hexa */

    union float_bytes {
       float val;
       unsigned char bytes[sizeof(float)];
    } data;

    data.val = x;
    for (int i = 0; i < sizeof(float); i++) 
          printf("Byte %d: %.2x\n", i, data.bytes[i]);

    data.val *= 2;   /* Doing something with the float value */
    x = data.val;    /* Retrieving the float value           */
    printf("%.4f\n", data.val);

    getchar();
 }
Run Code Online (Sandbox Code Playgroud)

如您所见,完全没有必要使用memcpy或指针......

union方法易于理解,标准且快速.

编辑.

我将解释为什么这种方法在C(C99)中有效.

  • [5.2.4.2.1(1)]一个字节有CHAR_BIT位(整数常数> = 8,在几乎情况下为8).
  • [6.2.6.1(3)]unsigned char类型使用其所有位来表示对象的值,该值是纯二进制表示中的非负整数.这意味着没有用于任何其他外部purpouse的填充位或位.(同样的事情不能保证signed charchar类型).
  • [6.2.6.1(2)]每个非位域类型在存储器中表示为连续的字节序列.
  • [6.2.6.1(4)](引用)"存储在任何其他对象类型的非位字段对象中的值由n×CHAR_BIT位组成,其中n是该类型对象的大小(以字节为单位).可以复制到类型的对象中unsigned char [n](例如,通过memcpy); [...]"
  • [6.7.2.1(14)]指向适当转换的结构对象(特别是联合)的指针指向其初始成员.(因此,在联合的开头没有填充字节).
  • [6.5(7)]可以通过字符类型访问对象的内容:

对象的存储值只能由具有以下类型之一的左值表达式访问:
- 与对象的有效类型兼容的类型,
- 与对象的有效类型兼容的类型的限定版本,
-与对象的有效类型对应的有符号或无符号类型的类型,
- 对应于对象有效类型的限定版本的有符号或无符号类型,
- 包含一个类型的聚合或联合类型其成员中的上述类型(包括递归地,子聚合或包含联合的成员),或
- 字符类型

更多信息:

谷歌小组中的讨论
类型惩罚

编辑2

标准C99的另一个细节:

  • [6.5.2.3(3)脚注82] 允许打字:

如果用于访问union对象内容的成员与上次用于在对象中存储值的成员不同,则将值的对象表示的相应部分重新解释为新类型中的对象表示形式在6.2.6中描述(一个过程有时称为"类型双关语").这可能是陷阱表示.

  • 我想要注意,虽然这可能在C中有效(C99,我认为,但不是C89?),这在C++中是未定义的行为.以防任何C++用户走过去看看. (3认同)