【问题标题】:C/C++ -- Bitfields as booleans?C/C++——位域作为布尔值?
【发布时间】:2018-04-06 23:59:29
【问题描述】:

我目前正在处理一个基于 SigFox 的物联网设备,它可以发送有效负载最大为 12 字节的消息。这意味着芯片制造商通常必须发挥创造力。我目前正在处理如下所示的消息:

typedef struct {
    byte MsgId; // Message Identification Value = 0x01
    unsigned int Start :1; // Start Message
    unsigned int Move :1; // Object Moving
    unsigned int Stop :1; // Object Stopped
    unsigned int Vibr :1; // Vibration Detected
    int16 Temp; // Temperature in 0,01 degC
    byte GPSFixAge; // bit 0..7 = Age of last GPS Fix in Minutes,
    byte SatCnt_HiLL; // bit 0..4 = SatInFix, bit5 Latitude 25 bit 6,7 = Longitude 25,26
    byte Lat[3]; // bit 0..23 = latitude bit 0..23
    byte Lon[3]; // bit 0..23 = longitude bit 0..23
}

我想 Start-Move-Stop-Vibr 数据可能应该被解释为布尔值,但它被编码为位域半字节以节省空间。我唯一不知道的是我是否应该考虑 start 是最不重要的位还是最重要的位。 F.e:

0x 00 8 ...

这里的 8 代表 Start-Move-Stop-Vibr 数据,其中最高有效位最高。但这是否意味着消息是 Start 类型或 Vibr?

【问题讨论】:

  • C 标准由实现决定如何将位域打包到包含对象中。因此,将位域放入消息定义中是不好的做法。相反,您应该有一个byte Flags,并使用按位运算来提取位。
  • 参考设备制造商可能比猜测更可靠。或者,如果绝望地查看多条消息,则振动设备并查看它发送的内容。或者使用水晶球。
  • 如何知道构成 Temp 值的两个字节是小端还是大端?关键是你不能确定只给定这个结构定义,位域中位的顺序也是如此。
  • 你可以直接问 SigFox 的人——见build.sigfox.com/steps/technical-quickstart#get-started-links
  • 跨编译域使用结构是一个非常非常糟糕的主意。一般来说,使用位域同样糟糕,如果在编译域中使用结构的一部分,情况会更糟。您正在为自己创造工作和维护以及令人头疼的问题。这是您应该不惜一切代价避免使用的语言的一个酥油高手功能。

标签: c embedded iot bit-fields


【解决方案1】:

我想 Start-Move-Stop-Vibr 数据可能应该被解释为布尔值,但它被编码为位域半字节以节省空间。

相反,他们尝试使用位域对某个二进制表示进行建模。这是高度特定于编译器的,所以这样的代码只能在特定的编译器上工作。

我唯一不知道的是我应该考虑 start 是最不重要的位还是最重要的位

您无法知道,标准未指定哪个位最重要。此外,CPU(可能还有网络协议)字节序可能会在这里发挥作用。

了解这一点的唯一方法是阅读特定的编译器文档。

这就是为什么一般的结构和特别是位域不适合映射原始二进制数据的原因。编写此代码的唯一可移植方式是使用原始的uint8_t 数组缓冲区,然后可以将其反序列化为各种变量。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-12-26
    • 2013-08-13
    • 2012-06-05
    • 1970-01-01
    相关资源
    最近更新 更多