【问题标题】:C BitWise - What does "1 << (num - 1)" and "|=" do?C BitWise - "1 << (num - 1)" 和 "|=" 有什么作用?
【发布时间】:2016-11-11 15:53:28
【问题描述】:

你能告诉我 convertLedNumberToBit 和 LedDriver_TurnOn 是做什么的吗?我不明白1 &lt;&lt; (num - 1)|= 发生了什么

static uint16_t * ledsAddress;

static uint16_t convertLedNumberToBit(int ledNumber)
{
    return  1 << (ledNumber - 1);
}
void LedDriver_TurnOn(int ledNumber)
{
    *ledsAddress |= convertLedNumberToBit(ledNumber);
}

【问题讨论】:

  • 更好的代码避免使用有符号整数数学和位。建议return 1u &lt;&lt; (ledNumber - 1);(加你)
  • @chux 在这种情况下,如果他们忽略了 u 会有什么问题?
  • 在 16 位处理器上,在 2016 年常见于嵌入式处理器,1 &lt;&lt; 15 是未定义的行为参见 C11 §6.5.7 4. 使用 1u &lt;&lt; 15,它定义良好并且按预期运行。
  • 好的。谢谢你的评论。你也应该发布一个答案。

标签: c hex bit-shift


【解决方案1】:

&lt;&lt; 是向左移位。二进制中的1uint16_t0b0000000000000001,因此当您向左移动ledNumber-1 的数量时,结果是uint16_t,其中一位设置为ledNumber 指定的位置。

根据变量名ledNumber,我猜这个函数设置了一个特定的LED来工作。

| 对其传递的两个操作数执行按位或。

例如,

byte b = 0x0A | 0x50;

如果您查看0x0A0x50 的底层位,它们分别是0b000010100b01010000。与 OR 运算符结合使用时,b 中的结果为0b01011010,或十六进制的0x5A

|= 是按位或赋值。 |= 类似于 +=-= 之类的运算符,因为它将对两个操作数执行按位或,然后将结果存储在左运算符中。

byte b = 0x0A;
b |= 0x50;

// after this b = 0x5A

【讨论】:

  • @yano,这毕竟是我自己的答案:)
  • 详细说明“所以当你左移数量 ledNumber-1 时,结果是 uint16_t”。 uint16_t 首先被提升为 intunsigned,然后转移。因此,结果的类型和符号可能与uint16_t 不同。 IAC,OP 的代码以int 开头,然后转换为uint16_t。如果将 1 位移到符号位置,则会出现问题。
  • @chux 所以如果将 17 传递给函数,将填充有符号位?
  • @Robben_Ford_Fan_boy 将 1 移入 int 的符号位是未定义的行为。无法转移到 uint16_t 的符号位,因为它没有符号位,因此 convertLedNumberToBit() 永远不会返回其不存在的符号位集。
【解决方案2】:

要在 I/O 端口ledsAddress 上打开 LED[ledNumber],需要将等效位设置为“1”。但是,在更改 I/O 端口值时,您必须保持所有其他 LED 的状态仍为“ON”。

convertLedNumberToBit(int ledNumber) 使用掩码 b0000000000000001(16 位)通过切换到 (ledNumber-1) 的左侧将 ledNumber 位设置为“1”{当 ledNumber 为 1 时不需要移位。

例如:(ledNumber = 4) => 返回值为b0000000000001000= 0x0008

然后调用 |= convertLedNumberToBit(ledNumber) 将仅强制 ledNumber 位为“1”,而不通过二进制或更改其他位。

例如:(led1、led3 和 led7 为“开”) 在 OR b0000000001000101 = 0x0045 之前。 LedDriver_TurnOn(4) => b0000000000001000= 0x0008 在 OR b0000000001001101 = 0x004D 之后。

要“关闭”同一个 LED,只需将 OR 函数替换为 NOT 掩码的 AND 函数即可。

void LedDriver_TurnOff(int ledNumber)
{
    *ledsAddress &= ~(convertLedNumberToBit(ledNumber));
}

【讨论】:

    【解决方案3】:

    cppreference - Arithmetic operators 救援

    按位移位运算符表达式具有以下形式
    lhs lhs >> rhs (2)
    1) lhs 左移 rhs 位
    2) lhs 右移 rhs 位

    所以1 &lt;&lt; (ledNumber - 1) 将最低有效位向左移动,例如如果ledNumber = 5

    0x0001 << (5 - 1)
    

    会变成

    0x0010
    

    还有cppreference - Assignment operators

    |= 是一个(按位或)赋值运算符,其中

    *ledsAddress |= convertLedNumberToBit(ledNumber);
    

    等价于

    *ledsAddress = *ledsAddress | convertLedNumberToBit(ledNumber);
    

    【讨论】:

    • 你的例子不正确吗?结果会不会是0x10000
    • 5 - 1 = 4, 0x0001
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-01-24
    • 2016-04-22
    • 2013-08-24
    • 2017-01-27
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多