【问题标题】:How to copy MSB to rest of the byte?如何将 MSB 复制到其余字节?
【发布时间】:2016-05-13 19:32:26
【问题描述】:

在中断子程序(每 5 µs 调用一次)中,我需要检查一个字节的 MSB 并将其复制到该字节的其余部分。

我需要做类似的事情:

if(MSB == 1){byte = 0b11111111}
else{byte = 0b00000000}

我需要它让它快,因为它在一个中断子程序上,而且上面还有一些代码,所以效率正在调用。

因此,我不想使用任何 if、switch、select 或 >> 操作数,因为我认为它会减慢进程。如果我错了,那我就走“简单”的路。

我尝试过的:

byte = byte & 0b100000000

这给了我0b10000000 或0b00000000。

但我需要第一个成为0b11111111。

我想我在某处(加上其他门)错过了一个 OR。我不知道,我的直觉告诉我这应该很容易,但现在不适合我。

【问题讨论】:

  • 你展示的条件确实够用了。而且它将比任何位黑客更具可读性。
  • 您使用的是 C 语言吗?或者,您是在 asm 中执行此操作吗?如果您使用带符号的右移方法,请查看微控制器的 ISA 参考手册以获取算术右移操作码,以确保 [它可能有效]。或者,只需创建一个测试用例。在 C 中,只需反汇编代码以确保获得预期的操作码。
  • @Craig Estey:我正在使用 C。谢谢,我记住了。
  • @Eugene Sh:因为它在中断子程序中,所以速度比清晰度更宝贵。如果没有,我会选择有条件的。
  • 刚刚在 x86 上对此进行了测试,使用 -O2 执行 m = (m & 0x80) ? 0xFF : 0x00 将导致优化器生成单个 sar inst(即它想通了)。我认为这很可能是因为我之前已经看到过类似的“针孔”优化,用于类似这样的有用/常见构造。因此,具有讽刺意味的是,您的 first 代码示例将生成最佳代码 ...

标签: c bit-manipulation microcontroller interrupt


【解决方案1】:

诀窍是为您的byte 变量使用带符号的类型,例如int8_t,并利用右移操作的符号扩展 功能:

byte = byte >> 7;

Demo.

右移速度非常快 - 大多数现代(甚至不那么现代)CPU 上的一条指令。

之所以有效,是因为 >> 在有符号操作数上会在左侧插入符号位以保留其操作数的符号。这称为符号扩展。

注意:从技术上讲,这种行为是实现定义的,因此不是普遍可移植的。谢谢Eugene Sh. 的评论和reference。

【讨论】:

  • 这很可爱。使字节签名,它变得微不足道。很好的答案。
  • 移位有符号负整数的结果是实现定义的。 port70.net/~nsz/c/c11/n1570.html#6.5.7p5
  • @EugeneSh。感谢您的参考和评论,我已经习惯了将其实现为算术移位,以至于我没有意识到它是实现定义的。我编辑了答案以包含您的参考。
  • 有时非int 类型上的符号扩展需要多条指令:实际发生的情况是编译器首先左移 24 位,然后右移 31。如果是这种情况,那就再好不过了而不是比较后的条件移动。
  • @user3528438 OP 在单个字节上运行,因此他的嵌入式编译器应该生成单个 ASR 指令。
【解决方案2】:

编辑:我的回答让人们感到困惑,因为我没有指定无符号字节。这里我的假设是B 是unsigned char 类型。正如下面的一条评论所指出的,我可以省略&1。这没有其他张贴者提出的有符号字节解决方案那么快,但是这段代码应该是可移植的(一旦了解B 是无符号类型)。

 B = -((B >> 7)&1)

负数我们是朋友。顺便说一句,移位应该很快。

【讨论】:

  • 它不是很便携
  • @EugeneSh。是什么让你觉得这不是便携的?
  • 否定的1 不是111...1 在每个表示中。 C 不保证 2 的补码。
  • 我在我的回答中假设了无符号类型。另一张海报有签名类型,比我的回答更有效率。
  • 实际上,您可以省略&1,因为无符号字节的B >> 7 只有 1 或0。而且,任何体面的优化器都可能无论如何都会转换代码.
【解决方案3】:

MSB 实际上是数字的符号位。负数为 1,正数为 0。 所以最简单的方法是

if(byte < 0)
{
    byte = -1;
}
else
{
    byte = 0;
}

因为 -1 = 11111111 二进制。

如果是无符号整数,只需简单地将其类型转换为有符号值,然后如上所述再次比较它。

【讨论】:

  • 值 -1 不一定是所有 1 位,因为 C 允许使用其他有符号格式,如 1 的补码和符号幅度
  • @LưuVĩnhPhúc 你能举个例子吗?
  • -1 可以是 11111110 的补码,10000001 的符号幅度,假设 8 位字节 Representation of negative numbers in C?
  • @LưuVĩnhPhúc,在这两种情况下(一个补码或符号大小),MSB 保持不变(即 1 表示负数)。
  • 没有。 C 中带符号类型的右移是implementation defined behavior。如果始终填写有符号位,则 -1 可能会变为 -0 或 -64 作为补码和符号幅度
猜你喜欢
  • 1970-01-01
  • 2012-06-04
  • 2022-11-25
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-01-25
  • 2015-02-14
  • 2014-06-02
相关资源
最近更新 更多