gpt4 book ai didi

c - 我应该使用位域来映射传入的串行数据吗?

转载 作者:行者123 更新时间:2023-12-04 13:19:20 26 4
gpt4 key购买 nike

我们有数据通过串行(蓝牙)传入,映射到特定结构。结构的某些部分是子字节大小,因此“显而易见”的解决方案是将传入数据映射到位字段。我无法解决的是机器或编译器的位字节序是否会影响它(这很难测试),以及我是否应该完全放弃位域。

例如,我们有一个 1.5 字节的数据,所以我们使用了结构:

{
uint8_t data1; // lsb
uint8_t data2:4; // msb
uint8_t reserved:4;
} Data;

保留位始终为 1

例如,如果传入的数据为 0xD2,0xF4,则值为 0x04D2,即 1234。

我们使用的结构总是在我们测试过的系统上工作,但我们需要它尽可能地可移植。

我的问题是:
  • 威尔data1无论字节序如何,始终代表预期的正确值(我假设是,并且硬件/软件接口(interface)应该始终正确处理单个完整字节 - 如果发送 0xD2,则应接收 0xD2)?
  • 可以data2reserved走错路,用 data2代表高4位而不是低4位?

  • 如果是:
  • 位字节序(通常)是否取决于字节字节序,还是它们可以完全不同?
  • 位字节序是由硬件还是编译器决定的?似乎英特尔上的所有 linux 系统都是一样的 - ARM 也是如此吗? (如果我们可以说我们可以支持所有 Intel 和 ARM linux 版本,我们应该没问题)
  • 是否有一种简单的方法可以在编译器中确定它是哪种方式,并在需要时保留位字段条目?

  • 虽然位域是映射传入数据的最简洁的代码方式,但我想我只是想知道放弃它们是否更安全,并使用类似的东西:
    struct {
    uint8_t data1; // lsb (0xFF)
    uint8_t data2; // msb (0x0F) & reserved (0xF0)
    } Data;

    Data d;

    int value = (d.data2 & 0x0F) << 16 + d.data1

    我们首先不这样做的原因是因为许多数据字段小于 1 个字节,而不是超过 1 个 - 这意味着通常对于位字段我们不必做任何屏蔽和移位,所以后处理更简单。

    最佳答案

    Should I use bit-fields for mapping incoming serial data?



    不。位域有很多实现指定的行为,这使得使用它们成为一场噩梦。

    Will data1 always represent the correct value as expected regardless of endianness.



    是的,但那是因为 uint8_t是最小的可寻址单位:一个字节。对于较大的数据类型,您需要注意字节顺序。

    Could data2 and reserved be the wrong way around, with data2 representing the upper 4 bits instead of the lower 4 bits?



    是的。它们也可以位于不同的字节上。此外,编译器不必支持 uint8_t对于位域,即使它会支持其他类型。

    Is the bit endianness (generally) dependent on the byte endianness, or can they differ entirely?



    最低有效位总是在最低有效字节中,但在 C 中不可能确定该位在字节中的哪个位置。

    位移运算符给出了足够好的顺序的可靠抽象:对于数据类型 uint8_t (1u << 0)始终是最不重要的,并且 (1u << 7)对于所有编译器和所有体系结构,最重要的位。

    另一方面,位域的定义很差,以至于您无法通过定义的域的顺序来确定位的顺序。

    Is the bit-endianness determined by the hardware or the compiler?



    编译器决定数据类型如何映射到实际位,但硬件对其影响很大。对于位字段,同一硬件的两个不同编译器可以将字段放置在不同的顺序中。

    Is there a simple way to determine in the compiler which way around it is, and reserve the bit-fields entries if needed?



    并不真地。如果可能的话,这取决于您的编译器如何执行此操作。

    Although bit-fields are the neatest way, code-wise, to map the incoming data, I suppose I am just wondering if it's a lot safer to just abandon them, and use something like:



    绝对放弃位域,但我也建议为此目的完全放弃结构,因为:
  • 您需要使用编译器扩展或手动工作来处理字节顺序。
  • 您需要使用编译器扩展来禁用填充以避免由于对齐限制造成的间隙。这会影响某些系统上的成员访问性能。
  • 您不能有可变宽度或可选字段。
  • 如果您不知道这些问题,很容易出现严格的别名违规。如果您为数据帧定义字节数组并将其转换为指向结构的指针,然后取消引用它,则在许多情况下都会遇到问题。

  • 相反,我建议手动进行。定义字节数组,然后通过在必要时使用位移位和掩码将它们分开来手动将每个字段写入其中。您可以为基本数据类型编写简单的可重用转换函数。

    关于c - 我应该使用位域来映射传入的串行数据吗?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/55823879/

    26 4 0
    Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
    广告合作:1813099741@qq.com 6ren.com