C - 将两个 uint32_t 组合成一个 double
C - combine two uint32_t to a double
您好,我正在研究两种协议之间的套接字转换。我从一个二进制文件中读取并将解析后的 header 存储到一个 uint32_t 类型的数组中。然后我从数组中取出字段并将它们转换为相应的类型。到目前为止 uint32_t
/int32_t
/uint16_t
到 int32_t
工作正常。
但是,当我尝试合并两个 uint32_t(一个接一个地附加)然后将这个 64 位长数据转换为双精度数据时,我得到了各种错误的输出。
作为 C 编程的新手,我正在努力学习 double
/ float
表示的计算机方法。
基本上我想做的是:在不改变两个uint32_t
的位模式的情况下,concast一个接一个地拼接成一个64位的数据,然后将数据转换为 double
。最重要的是不要改变位模式,因为那部分位流应该是 double
.
以下为部分代码:
uint32_t* buffer = (uint32_t*) malloc (arraySize * sizeof(uint32_t));
...
double outputSampleRate = ((union { double i; double outputSampleRate; })
{ .i = ((uint64_t)buffer[6] << 32 | (uint64_t)buffer[7])}).outputSampleRate;
输入文件中的数据:
35.5
我的代码后的值:
4630192998146113536.000000
另外,有没有更好的方法来处理套接字header解析?
您的联合定义不正确,您希望 i
定义为 uint64_t
:
double outputSampleRate = ((union { uint64_t i; double d; })
{ .i = ((uint64_t)buffer[6] << 32 | (uint64_t)buffer[7])}).d;
您也可能 运行 遇到字节顺序问题。试试小端:
double outputSampleRate = ((union { unt64_t i; double d; })
{ .i = ((uint64_t)buffer[7] << 32) | (uint64_t)buffer[6]}).d;
通过 union
重新解释表示的位实际上得到了 C 标准的支持,称为类型双关。如果这些位表示目标类型的陷阱值,则不能保证工作。
您可以尝试其他转换和技巧:试试您的运气并使用指针转换:
double outputSampleRate = *(uint64_t*)&buffer[6];
另一种强制类型双关的方法是使用 memcpy
函数:
double outputSampleRate;
uint64_t temp = ((uint64_t)buffer[7] << 32) | (uint64_t)buffer[6];
memcpy(&outputSampleRate, &temp, sizeof(outputSampleRate));
或者简单地说:
double outputSampleRate;
memcpy(&outputSampleRate, &buffer[6], sizeof(outputSampleRate));
但它似乎也不能保证有效,尽管我在生产代码中看到了上述两种情况的一些实例。
通过联合重新解释位模式需要联合元素具有正确的类型。你的 union 有两个 doubles
,所以当你从一个读取时,它与另一个具有相同的值。从 uint32_t
到 double
的转换将保留数值结果,解释 "garbage",这实际上只是将 double
重新解释为整数。您还需要使用正确的字节顺序(低字在前?高字在前?),最简单的方法是完全避免位移。
double outputSampleRate = ((union { uint32_t i[2]; double d; })
{ .i = { buffer[6], buffer[7] } }).d;
您可以使用 uint64_t i
但是...何必呢?
您也可以使用 memcpy()
复制字节...
double outputSampleRate;
memcpy(&outputSampleRate, &buffer[6], sizeof(outputSampleRate));
通常的注意事项适用:虽然这些解决方案相对可移植,但它们没有考虑字节序问题,并且它们不会在违反您的假设的系统上运行,例如double
有多大,但做出这些假设通常是安全的。
您好,我正在研究两种协议之间的套接字转换。我从一个二进制文件中读取并将解析后的 header 存储到一个 uint32_t 类型的数组中。然后我从数组中取出字段并将它们转换为相应的类型。到目前为止 uint32_t
/int32_t
/uint16_t
到 int32_t
工作正常。
但是,当我尝试合并两个 uint32_t(一个接一个地附加)然后将这个 64 位长数据转换为双精度数据时,我得到了各种错误的输出。
作为 C 编程的新手,我正在努力学习 double
/ float
表示的计算机方法。
基本上我想做的是:在不改变两个uint32_t
的位模式的情况下,concast一个接一个地拼接成一个64位的数据,然后将数据转换为 double
。最重要的是不要改变位模式,因为那部分位流应该是 double
.
以下为部分代码:
uint32_t* buffer = (uint32_t*) malloc (arraySize * sizeof(uint32_t));
...
double outputSampleRate = ((union { double i; double outputSampleRate; })
{ .i = ((uint64_t)buffer[6] << 32 | (uint64_t)buffer[7])}).outputSampleRate;
输入文件中的数据:
35.5
我的代码后的值:
4630192998146113536.000000
另外,有没有更好的方法来处理套接字header解析?
您的联合定义不正确,您希望 i
定义为 uint64_t
:
double outputSampleRate = ((union { uint64_t i; double d; })
{ .i = ((uint64_t)buffer[6] << 32 | (uint64_t)buffer[7])}).d;
您也可能 运行 遇到字节顺序问题。试试小端:
double outputSampleRate = ((union { unt64_t i; double d; })
{ .i = ((uint64_t)buffer[7] << 32) | (uint64_t)buffer[6]}).d;
通过 union
重新解释表示的位实际上得到了 C 标准的支持,称为类型双关。如果这些位表示目标类型的陷阱值,则不能保证工作。
您可以尝试其他转换和技巧:试试您的运气并使用指针转换:
double outputSampleRate = *(uint64_t*)&buffer[6];
另一种强制类型双关的方法是使用 memcpy
函数:
double outputSampleRate;
uint64_t temp = ((uint64_t)buffer[7] << 32) | (uint64_t)buffer[6];
memcpy(&outputSampleRate, &temp, sizeof(outputSampleRate));
或者简单地说:
double outputSampleRate;
memcpy(&outputSampleRate, &buffer[6], sizeof(outputSampleRate));
但它似乎也不能保证有效,尽管我在生产代码中看到了上述两种情况的一些实例。
通过联合重新解释位模式需要联合元素具有正确的类型。你的 union 有两个 doubles
,所以当你从一个读取时,它与另一个具有相同的值。从 uint32_t
到 double
的转换将保留数值结果,解释 "garbage",这实际上只是将 double
重新解释为整数。您还需要使用正确的字节顺序(低字在前?高字在前?),最简单的方法是完全避免位移。
double outputSampleRate = ((union { uint32_t i[2]; double d; })
{ .i = { buffer[6], buffer[7] } }).d;
您可以使用 uint64_t i
但是...何必呢?
您也可以使用 memcpy()
复制字节...
double outputSampleRate;
memcpy(&outputSampleRate, &buffer[6], sizeof(outputSampleRate));
通常的注意事项适用:虽然这些解决方案相对可移植,但它们没有考虑字节序问题,并且它们不会在违反您的假设的系统上运行,例如double
有多大,但做出这些假设通常是安全的。