位移、掩码还是位域结构体?

4

我是一位新手,对二进制编程不够熟悉。我尝试使用一个已有的协议,该协议可以发送三种不同类型的消息。

第一种消息是由16位结构组成:

struct digital 
{
 unsigned int type:2;
 unsigned int highlow:1;
 unsigned int sig1:5;
 unsigned int :1;
 unsigned int sig2:7;
};

前两位(在我的结构体中为type)始终为10。第三位highlow决定信号是开还是关,sig1和sig2共同定义了信号的12位索引。这个索引通过0来分隔两个字节,该0始终在第7位。

类型2是一个32位结构。它有一个2位类型,一个10位索引和一个16位值,其中0位分别位于第27、23、15和7个位置。按位域结构表示如下:

struct analog 
{
 unsigned int type:2;
 unsigned int val1:2;
 unsigned int :1;
 unsigned int sig1:3;
 unsigned int :1;
 unsigned int sig2:7;
 unsigned int :1;
 unsigned int val2:7;
 unsigned int :1;
 unsigned int val3:7;
};

sig1和sig2一起形成了10位索引。val1 + val2 + val3一起形成了10位索引处信号的16位值。
如果我能理解如何使用前两个结构体,我想我可以弄清楚第三个。
我的问题是,是否有一种方法可以分配单个值并让程序计算需要放入val1、val2和val3的位?
我已经阅读了有关位移、位字段结构和填充0的内容。结构似乎是正确的方法,但我不确定如何实现它。我看到的所有位打包示例都没有将值分开的方式。最终,我希望能够创建一个模拟结构,分配一个索引(i=252)和一个值(v=32768),然后就完成了。
如果有人能建议适当的方法或提供类似示例的链接,我将非常感激。如果有关系的话,这段代码将被合并到一个更大的Objective-C应用程序中。
谢谢。
Brad

我不确定我理解你的意思...当你说“val1 + val2 + val3 together”时,你是指连接还是简单的加法?如果是连接,那么你的问题仅仅是关于如何在给定连接版本的适当位置插入零吗? - int3
这是串联。值是一个16位的值,其位需要分成三个“段”。因此,val1保存Value的3个最高有效位,然后是val2的7个位,最后是val3的7个最低有效位。因此,问题在于在正确的位置插入0,但在Analog结构的情况下,信号索引(非0)也需要插入到Value的中间。谢谢。 - Brad
3个回答

4
您可以通过一系列的移位、与和或操作来完成此操作。我已经为 Type 2 完成了 10 位索引部分:
unsigned int i = 252;

analog a = (analog)(((i << 16) & 0x7f0000) | (i << 17) & 0x7000000);

基本上,这段代码的作用是将 int i 中感兴趣的 10 位移至 16-25 范围内,然后使用掩码 0x7f0000 进行 and 操作,以将第 22-31 位设置为零。它还将另一份 10 位的副本移至 17-26 范围内,然后使用掩码 0x7000000 进行 and 操作,以将第 0-22 和第 26-31 位设置为零。然后将这两个值进行 or 操作,以创建所需的零分隔值。
.. 我不能完全确定我是否正确计算了比特掩码,但我希望你已经有了想法。只需进行移位、按位与操作和按位或合并即可。 编辑:方法 2:
analog a;
a.sig1 = (i & 0x7f); // mask out bit 8 onwards
a.sig2 = ((i<<1) & 0x700); // shift left by one, then mask out bits 0-8

经过再次考虑,方法2更易读,因此您应该使用它。


0

你不必这样做,这就是 union 关键字的作用 - 你可以同时指定所有位,或通过使用不同名称引用相同的位,一次性设置它们。


0

不应使用C结构体位域,因为位域的物理布局是未定义的。虽然您可以弄清楚编译器正在做什么并使布局与底层数据匹配,但如果您切换到不同的编译器甚至更新编译器,则代码可能无法工作。

我知道这很麻烦,但请自己进行位操作。


2
有时使用位域来解析消息是完全合理的。例如,在嵌入式应用程序中,程序与DSP芯片的能力紧密相连,不必担心可移植性,因为平台更改会破坏一切。了解编译器如何处理位域,并利用它可以让您编写更清晰的代码。 - AShelly
4
也许我有所疏漏,但在结构体的关闭大括号后添加__attribute__((packed));应该可以保留顺序和大小,防止编译器对结构体进行干扰。 - Warpling

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接