如何以小端顺序发送数据 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