坑的由来
- 都知道在网络通信时要把网络字节序转化为主机字节序才行,但是c++里的标准库函数
ntohl
默认是转换32位字节序的数据,也就是说默认是转换float类型的数据; - 而ur机械臂30003端口发送的是double类型的数据,没法直接用
ntohl
进行转换。
小贴士
- float是4字节,32位;double是8字节,64位。
- 在网络传输中,数据通常以字节为单位进行编码,这种编码方式被称为网络字节序,它主要用于确保数据在不同主机之间传输时不会受到主机不同字节序的影响。
- 网络字节序采用大端模式,即高位字节在前,低位字节在后。
- 而主机字节序则可能因主机的不同而有所差异,常见的有两种:大端模式和小端模式。小端模式的主机字节序低位字节在前,高位字节在后,与人的直观感受相符。
解决办法
需要自己编写一个函数做这个转换,以下是一种方式:
double ntohd(double netDouble)
{
uint64_t netInt = be64toh(*((uint64_t*)&netDouble));
return *((double*)&netInt);
}
逐行解析一下:
uint64_t netInt = be64toh(*((uint64_t*)&netDouble));
这句话做了:
&netDouble
: 获取netDouble
的内存地址。(uint64_t*)&netDouble
: 将该地址强制转换为uint64_t
类型的指针。这是为了将双精度浮点数的内存表示视为一个64位的无符号整数。*((uint64_t*)&netDouble)
: 通过解引用这个指针,我们得到了一个uint64_t
类型的值,该值在内存中的表示与netDouble
完全相同。be64toh(...)
: 这是一个库函数,用于将64位的无符号整数从网络字节序(big-endian)转换为主机字节序。
return *((double*)&netInt);
同理,这句话:
-
&netInt
: 获取netInt
的内存地址。 -
(double*)&netInt
: 将该地址强制转换为double
类型的指针。这是为了将64位的无符号整数的内存表示视为一个双精度浮点数。 -
*((double*)&netInt)
: 通过解引用这个指针,我们得到了一个double
类型的值,该值在内存中的表示与netInt
完全相同。 -
最后,这个值被返回。
附录(ur机械臂30003端口机械臂法兰位姿数据解析)
double x, y, z, rx, ry, rz;
char data[1140];
int recvLen = recv(socket_, data, 1140, 0);
if (recvLen > 0)
{
memcpy(&x, data+444, sizeof(double));
memcpy(&y, data+452, sizeof(double));
memcpy(&z, data+460, sizeof(double));
memcpy(&rx, data+468, sizeof(double));
memcpy(&ry, data+476, sizeof(double));
memcpy(&rz, data+484, sizeof(double));
x = ntohd(x);
y = ntohd(y);
z = ntohd(z);
rx = ntohd(rx);
ry = ntohd(ry);
rz = ntohd(rz);
- 上面的代码就是对ur机械臂30003端口机械臂法兰位姿的解析,如果将
ntohd
换成dtohl
会解析出全是0的错误数据。