如何以小端顺序发送数据 C
How to send data in little endian order C
我正在与要求我向其发送 2 个有符号字节的电路板通信。
数据类型说明
我需要发送什么
我需要按位操作还是可以像下面这样发送 16 位整数?
int16_t rc_min_angle = -90;
int16_t rc_max_angle = 120;
write(fd, &rc_min_angle, 2);
write(fd, &rc_max_angle, 2);
int16_t
具有正确的大小,但可能是也可能不是正确的字节顺序。为确保小端顺序使用宏,例如来自 endian.h:
的宏
#define _BSD_SOURCE
#include <endian.h>
...
uint16_t ec_min_angle_le = htole16(ec_min_angle);
uint16_t ec_max_angle_le = htole16(ec_max_angle);
write(fd, &ec_min_angle_le, 2);
write(fd, &ec_max_angle_le, 2);
这里的htole16
代表"host to little endian 16-bit"。它将主机的本机字节顺序转换为小字节序:如果机器是大字节序,它交换字节;如果它是 little endian,则它是一个空操作。
另请注意,您将值的地址传递给 write()
,而不是值本身。遗憾的是,我们无法内联调用并编写 write(fd, htole16(ec_min_angle_le), 2)
.
如果你不需要它是泛型的,你可以简单地做:
#include <stdint.h>
#include <unistd.h>
/*most optimizers will turn this into `return 1;`*/
_Bool little_endian_eh() { uint16_t x = 1; return *(char *)&x; }
void swap2bytes(void *X) { char *x=X,t; t=x[0]; x[0]=x[1]; x[1]=t; }
int main()
{
int16_t rc_min_angle = -90;
int16_t rc_max_angle = 120;
//this'll very likely be a noop since most machines
//are little-endian
if(!little_endian_eh()){
swap2bytes(&rc_min_angle);
swap2bytes(&rc_max_angle);
}
//TODO error checking on write calls
int fd =1;
write(fd, &rc_min_angle, 2);
write(fd, &rc_max_angle, 2);
}
要发送小端数据,您可以手动生成字节:
int write_le(int fd, int16_t val) {
unsigned char val_le[2] = {
val & 0xff, (uint16_t) val >> 8
};
int nwritten = 0, total = 2;
while (nwritten < total) {
int n = write(fd, val_le + nwritten, total - nwritten);
if (n == -1)
return nwritten > 0 ? nwritten : -1;
nwritten += n;
}
return nwritten;
}
一个好的编译器会识别出代码什么都不做,并在小端平台上将位操作编译为无操作。 (参见例如 gcc 为变体生成相同的代码 with and without bit-twiddling。)
另请注意,您不应该忽略 write()
的 return 值 - 它不仅会遇到错误,而且还可能写入少于您提供的值,在这种情况下,您必须重复写入。
如果端函数不可用,只需按小端顺序写入字节即可。
可能使用复合文字。
// v------------- compound literal ---------------v
write(fd, &(uint8_t[2]){rc_min_angle%256, ec_min_angle/256}, 2);
write(fd, &(uint8_t[2]){rc_max_angle%256, ec_max_angle/256}, 2);
// ^-- LS byte ---^ ^-- MS byte ---^
// &
我添加了 &
假设 write()
类似于 write(2) - Linux。
我正在与要求我向其发送 2 个有符号字节的电路板通信。
数据类型说明
我需要按位操作还是可以像下面这样发送 16 位整数?
int16_t rc_min_angle = -90;
int16_t rc_max_angle = 120;
write(fd, &rc_min_angle, 2);
write(fd, &rc_max_angle, 2);
int16_t
具有正确的大小,但可能是也可能不是正确的字节顺序。为确保小端顺序使用宏,例如来自 endian.h:
#define _BSD_SOURCE
#include <endian.h>
...
uint16_t ec_min_angle_le = htole16(ec_min_angle);
uint16_t ec_max_angle_le = htole16(ec_max_angle);
write(fd, &ec_min_angle_le, 2);
write(fd, &ec_max_angle_le, 2);
这里的htole16
代表"host to little endian 16-bit"。它将主机的本机字节顺序转换为小字节序:如果机器是大字节序,它交换字节;如果它是 little endian,则它是一个空操作。
另请注意,您将值的地址传递给 write()
,而不是值本身。遗憾的是,我们无法内联调用并编写 write(fd, htole16(ec_min_angle_le), 2)
.
如果你不需要它是泛型的,你可以简单地做:
#include <stdint.h>
#include <unistd.h>
/*most optimizers will turn this into `return 1;`*/
_Bool little_endian_eh() { uint16_t x = 1; return *(char *)&x; }
void swap2bytes(void *X) { char *x=X,t; t=x[0]; x[0]=x[1]; x[1]=t; }
int main()
{
int16_t rc_min_angle = -90;
int16_t rc_max_angle = 120;
//this'll very likely be a noop since most machines
//are little-endian
if(!little_endian_eh()){
swap2bytes(&rc_min_angle);
swap2bytes(&rc_max_angle);
}
//TODO error checking on write calls
int fd =1;
write(fd, &rc_min_angle, 2);
write(fd, &rc_max_angle, 2);
}
要发送小端数据,您可以手动生成字节:
int write_le(int fd, int16_t val) {
unsigned char val_le[2] = {
val & 0xff, (uint16_t) val >> 8
};
int nwritten = 0, total = 2;
while (nwritten < total) {
int n = write(fd, val_le + nwritten, total - nwritten);
if (n == -1)
return nwritten > 0 ? nwritten : -1;
nwritten += n;
}
return nwritten;
}
一个好的编译器会识别出代码什么都不做,并在小端平台上将位操作编译为无操作。 (参见例如 gcc 为变体生成相同的代码 with and without bit-twiddling。)
另请注意,您不应该忽略 write()
的 return 值 - 它不仅会遇到错误,而且还可能写入少于您提供的值,在这种情况下,您必须重复写入。
如果端函数不可用,只需按小端顺序写入字节即可。
可能使用复合文字。
// v------------- compound literal ---------------v
write(fd, &(uint8_t[2]){rc_min_angle%256, ec_min_angle/256}, 2);
write(fd, &(uint8_t[2]){rc_max_angle%256, ec_max_angle/256}, 2);
// ^-- LS byte ---^ ^-- MS byte ---^
// &
我添加了 &
假设 write()
类似于 write(2) - Linux。