我应该使用位域来映射传入的串行数据吗? [英] Should I use bit-fields for mapping incoming serial data?

查看:65
本文介绍了我应该使用位域来映射传入的串行数据吗?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

We have data coming in over serial (Bluetooth), which maps to a particular structure. Some parts of the structure are sub-byte size, so the "obvious" solution is to map the incoming data to a bit-field. What I can't work out is whether the bit-endianness of the machine or compiler will affect it (which is difficult to test), and whether I should just abandon the bit-fields altogether.

例如,我们有一块1.5字节的数据,因此我们使用了以下结构:

For example, we have a piece of data which is 1.5 bytes, so we used the struct:

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

保留位始终为1

因此,例如,如果传入数据为0xD2,0xF4,则值为0x04D2或1234。

So for example, if the incoming data is 0xD2,0xF4, the value is 0x04D2, or 1234.

我们使用的结构始终在我们测试过的系统上运行

The struct we have used is always working on the systems we have tested on, but we need it to be as portable as possible.

我的问题是:


  • data1 始终代表期望的正确值,而不考虑字节顺序(我认为是,并且硬件/软件接口应始终正确处理该值)一个完整的字节-如果发送了0xD2,则应该接收到0xD2)?

  • Will data1 always represent the correct value as expected regardless of endianness (I assume yes, and that the hardware/software interface should always handle that correctly for a single, whole byte - if 0xD2 is sent, 0xD2 should be received)?

可以 data2 保留是错误的方法,其中 data2 代表高4位而不是低4位?

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

如果是:


  • (字节)字节顺序通常取决于字节的字节顺序吗?

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

位序由硬件还是由编译器确定?看来Intel上的所有linux系统都是相同的-ARM也是这样吗? (如果可以说我们可以支持所有Intel和ARM linux构建,那应该没问题)

Is the bit-endianness determined by the hardware or the compiler? It seems all linux systems on Intel are the same - is that true for ARM as well? (If we can say we can support all Intel and ARM linux builds, we should be OK)

是否有一种简单的方法可以确定编译器中的哪种方法

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:

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个字节-这意味着通常使用位字段,我们不必进行任何掩蔽和移位,因此后处理更加简单。

The reason we have not just done this in the first place is because a number of the data fields are less than 1 byte, rather than more than 1 - meaning that generally with a bit-field we don't have to do any masking and shifting, so the post-processing is simpler.

推荐答案


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

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

否位域具有许多实现指定的行为,这使使用它们成为一场噩梦。

No. Bit-fields have a lot of implementation specified behaviour that makes using them a nightmare.


无论数据1始终代表期望的正确值,无论字节序。

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

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

Yes, but that is because uint8_t is smallest possible addressable unit: a byte. For larger data types you need to take care of the byte endianness.


data2和reserved可能是错误的方法,data2表示是高4位而不是低4位?

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

是。它们也可以在不同的字节上。另外,即使编译器支持位类型,编译器也不必支持 uint8_t

Yes. They could also be on different bytes. Also, compiler doesn't have to support uint8_t for bitfields, even if it would support the type otherwise.


(字节序)位字节序通常取决于字节的字节序吗?

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

最低有效位将始终位于最低有效字节中,但是无法在C 中确定该位在字节中的何处。

The least signifact bit will always be in the least significant byte, but it's impossible to determine in C where in the byte the bit will be.

移位运算符给出了足够好的顺序的可靠抽象:对于数据类型 uint8_t (1u<< 0)始终是最低有效位,而(1u<< 7)最高有效位。

Bit shifting operators give reliable abstraction of the order that is good enough: For data type uint8_t the (1u << 0) is always the least significant and (1u << 7) the most significant bit, for all compilers and for all architectures.

另一方面,位字段定义太差,无法根据定义的字段的顺序确定位的顺序。

Bit-fields on the other hand are so poorly defined that you cannot determine the order of bits by the order of your defined fields.


是由硬件还是由编译器确定的位序?

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

编译器指示数据类型如何映射到实际位,但是硬件会对其产生重大影响。对于位域,使用相同硬件的两个不同的编译器可以按不同顺序放置域。

Compiler dictates how datatypes map to actual bits, but hardware heavily influences it. For bit-fields, two different compilers for the same hardware can put fields in different order.


是否有一种简单的方法可以确定编译器是如何解决的,并在需要时保留位字段条目?

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:

一定要放弃位域,但我也建议为此完全放弃结构,因为:

Definitely abandon bit-fields, but I would also recommend abandoning structures altogether for this purpose, because:


  • 您需要使用编译器扩展或手动操作来处理字节顺序。

  • You need to use compiler extensions or manual work to handle byte order.

您需要使用编译器扩展来禁用填充,以免由于对齐限制而产生间隙。这会影响某些系统上的成员访问性能。

You need to use compiler extensions to disable padding to avoid gaps due to alignment restrictions. This affects member access performance on some systems.

您不能具有可变宽度或可选字段。

You cannot have variable width or optional fields.

如果您不知道这些问题,则很容易遇到严格的别名冲突。如果您为数据帧定义字节数组并将其转换为结构指针然后取消引用,那么在很多情况下都会遇到问题。

It's very easy to have strict aliasing violations if you are unaware of those issues. If you define byte array for the data frame and cast that to pointer to structure and then dereference that, you have problems in many cases.

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

Instead I recommend doing it manually. Define byte array and then write each field into it manually by breaking them apart using bit shifting and masking when necessary. You can write a simple reusable conversion functions for the basic data types.

这篇关于我应该使用位域来映射传入的串行数据吗?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆