【问题标题】:Bit Shifting, Masking or a Bit Field Struct?位移、屏蔽或位域结构?
【发布时间】:2009-11-25 14:41:33
【问题描述】:

我不熟悉位。我正在尝试使用现有协议,该协议可以发送三种不同类型的消息。

类型 1 是 16 位结构:

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

前两位(类型,在我上面的结构中)总是 1 0 。第三位highlow决定信号是开还是关,sig1 + sig2共同定义了信号的12位索引。这个索引被一个 0 分割成两个字节,0 总是在第 7 位。

类型 2 是 32 位结构。它有一个 2 位的类型、一个 10 位的索引和一个 16 位的值,在 27、23、15 和 7 的位置上散布着 0。位域结构表示应该是这样的:

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 应用程序中。

谢谢。

布拉德

【问题讨论】:

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

标签: c objective-c bit-manipulation bit-fields


【解决方案1】:

您可以通过一系列轮班来完成此操作,ands 和 ors。我已经完成了 Type 2 的 10 位索引部分:

unsigned int i = 252;

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

基本上,这段代码所做的是将int i 中感兴趣的10 位移动到16 - 25 的范围内,然后ands 使用位掩码0x7f0000 将位22 - 31 设置为零。它还将 10 位的另一个副本移动到 17 - 26 范围内,然后使用位掩码 0x7000000 ands 将位 0 ​​- 22 和 26 - 31 设置为零。然后将ors 这两个值一起创建您想要的零分隔值。

.. 我不确定我是否正确计算了位掩码,但我希望你明白这一点。只需 shift、and-mask 和 or-merge。

编辑:方法二:

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 更具可读性,因此您应该使用它。

【讨论】:

    【解决方案2】:

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

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

    【讨论】:

    • 在某些情况下使用位域来解析消息是完全合理的。例如,在程序与 DSP 芯片功能密切相关的嵌入式应用程序中,没有理由担心可移植性,因为平台更改会破坏一切。弄清楚编译器如何处理位域,并利用它可以让你编写更简洁的代码。
    • 也许我遗漏了一些东西,但是在结构的右大括号之后添加 __attribute__((packed)); 应该保留顺序和大小,防止编译器弄乱你的结构。
    【解决方案3】:

    您不必这样做,这就是 union 关键字的用武之地 - 您可以同时指定所有位,或者通过引用不同名称的相同位,一次设置它们.

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2017-07-02
      • 1970-01-01
      • 1970-01-01
      • 2017-11-29
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多