【问题标题】:Extract unsigned values from certain bits in C# ushort从 C# ushort 中的某些位中提取无符号值
【发布时间】:2010-11-18 13:27:48
【问题描述】:

我需要一种从 unsigned short 中的某些位中提取值的好方法:

ushort里面4个告警的定义:

Name......Range.......Bits
Alarm4....0-15....13/16-16/16
Alarm3....0-15....9/16-12/16
Alarm2....0-15....5/16-8/16
Alarm1....0-15....1/16-4/16

ushort 的值:4383 或(二进制的1000100011111)

所以我想要实现的是:

1001100110011001
Alarm1.....Alarm2.....Alarm3......Alarm4
1001.......1001.......1001........1001

Gets translated into:
Alarm1....Alarm2....Alarm3....Alarm4
9............9............9............9

使用伪代码:

getValueFunc(ushort bits, int offset);  
ushort u = 4383;
UInt16 Alarm1Value = getValueFunc(u, 1);
UInt16 Alarm2Value = getValueFunc(u, 5);
UInt16 Alarm3Value = getValueFunc(u, 9);
UInt16 Alarm4Value = getValueFunc(u, 13);

问候, 约翰

【问题讨论】:

    标签: c# extract bit-manipulation bits


    【解决方案1】:
    int GetFromBits(ushort bits, int offset)
    {
     return (bits >> (offset - 1)) & 0xF;
    }
    

    【讨论】:

    • 非常感谢!这对于填充所有 16 位的情况非常有效。测试它,它工作,我能够提取所有的值。
    【解决方案2】:
    bool GetBit(ushort bits, int offset) {
        return (bits & (1<<offset)) != 0;
    }
    

    【讨论】:

    • 是的,它只提取单个位。我将指定的4个位提取出来,然后得到值,最大为15
    【解决方案3】:

    除非有特殊原因使用 ushort,否则我强烈建议您使用 enum flags。这是 C# 中按位运算的预期替代品。

    【讨论】:

      【解决方案4】:

      使用枚举:

      [Flags]
      public enum Alarm : int
      {
          AlarmValue1 = 0x1,
          AlarmValue2 = // the Hex Value,
          AlarmValue3 = // the Hex Value,
          AlarmValue4 = // the Hex Value
      
      }
      
      
      ushort myValue = 0x687;
      Alarm alarm = (Alarm) myValue;
      
      Console.WriteLine(alarm & AlarmValue3);
      

      【讨论】:

      • 我正在解释从硬件读取的数据,我希望每一位都有意义,但在这种情况下,每个警报可以有 1 到 15 个不同的状态,这使得事情变得更加复杂。跨度>
      【解决方案5】:

      使用枚举标志的 VB 示例

      Public Class Form1
      
          <FlagsAttribute()> _
          Public Enum Alarms As UShort
              'bits in short
              '1 1 1 1 1 1
              '5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0
              No_Alarms = 0 'do not change
      
              Alarm1All = &HF
              HighTemp1 = 1 << 0
              LowOilPress1 = 1 << 1
              HighRPM1 = 1 << 2
              LowRPM1 = 1 << 3
      
              Alarm2All = &HF0 'alarm two is a 4 bit value 0 - 15
              _bit0AL2 = 1 << 4
              _bit1AL2 = 1 << 5
              _bit2AL2 = 1 << 6
              _bit3AL2 = 1 << 7
      
              Alarm3All = &HF00
              Cond3_0 = 1 << 8
              Cond3_1 = 1 << 9
              Cond3_2 = 1 << 10
              Cond3_3 = 1 << 11
      
              Alarm4All = &HF000
              DoorAjar = 1 << 12
              O2Sensor = 1 << 13
              LightsOn = 1 << 14
              LowFuel = 1 << 15
      
              All_Alarms = &HFFFF 'do not change
      
              zAlarm1Offs = 0US
              zAlarm2Offs = 4US
              zAlarm3Offs = 8US
              zAlarm4Offs = 12US
          End Enum
      
          Private Sub Button1_Click(ByVal sender As System.Object, _
                                    ByVal e As System.EventArgs) Handles Button1.Click
      
              Dim foo As Alarms = Alarms.No_Alarms 'set no alarms
              debugAlarm(foo)
      
              'turn some alarms on
              foo = Alarms.HighTemp1 Or Alarms.LowOilPress1
              debugAlarm(foo)
      
              'turn some more on
              foo = foo Or Alarms._bit0AL2 Or Alarms._bit3AL2 Or Alarms.Cond3_2 Or Alarms.Cond3_3 Or Alarms.LightsOn Or Alarms.LowFuel
              debugAlarm(foo)
      
              'check Alarm4
              If (foo And Alarms.Alarm4All) <> Alarms.No_Alarms Then 'any fours on
                  'check which 4
                  If (foo And Alarms.DoorAjar) = Alarms.DoorAjar Then
                      'Cond4_0 on
                      Stop
                  ElseIf (foo And Alarms.O2Sensor) = Alarms.O2Sensor Then
                      'Cond4_1 on
                      Stop
                  ElseIf (foo And Alarms.LightsOn) = Alarms.LightsOn Then
                      'Cond4_2 on
                      foo = foo And (Alarms.All_Alarms Xor Alarms.LightsOn) 'turn off Cond4_2
                  ElseIf (foo And Alarms.LowFuel) = Alarms.LowFuel Then
                      'Cond4_3 on
                      Stop
                  End If
              End If
              debugAlarm(foo)
      
              'check Alarm2 
              If (foo And Alarms.Alarm2All) <> Alarms.No_Alarms Then 'any twos on
                  'check Alarm2 for values
                  Select Case CUShort(foo And Alarms.Alarm2All) 'foo And Alarms.Alarm2All
                      Case 1US << Alarms.zAlarm2Offs 'Alarms._bit0AL2
                          Stop
                      Case 2US << Alarms.zAlarm2Offs 'Alarms._bit1AL2
                          Stop
                      Case 3US << Alarms.zAlarm2Offs 'Alarms._bit0AL2 or Alarms._bit2AL2
                          Stop
                      Case 4US << Alarms.zAlarm2Offs
                          Stop
                      Case 5US << Alarms.zAlarm2Offs
                          Stop
                      Case 6US << Alarms.zAlarm2Offs
                          Stop
                      Case 7US << Alarms.zAlarm2Offs
                          Stop
                      Case 8US << Alarms.zAlarm2Offs
                          Stop
                      Case 9US << Alarms.zAlarm2Offs
                          debugAlarm(foo And Alarms.Alarm2All)
                          Stop
                      Case 10US << Alarms.zAlarm2Offs
                          Stop
                      Case 11US << Alarms.zAlarm2Offs
                          Stop
                      Case 12US << Alarms.zAlarm2Offs
                          Stop
                      Case 13US << Alarms.zAlarm2Offs
                          Stop
                      Case 14US << Alarms.zAlarm2Offs
                          Stop
                      Case 15US << Alarms.zAlarm2Offs
                          Stop
                  End Select
              End If
              debugAlarm(foo)
      
          End Sub
      
          Private Sub debugAlarm(ByVal _alarm As Alarms)
              Debug.WriteLine("")
              Dim asUshort As UShort = _alarm
              Debug.WriteLine(_alarm.ToString)
              Debug.WriteLine(Convert.ToString(asUshort, 2).PadLeft(16, "0"c))
          End Sub
      End Class
      

      【讨论】:

      • 我看到有人也在为柴油发电机组开发软件!!!我找到了一种更有效的方法来管理这些警报,它们非常棘手,因为它们每个都有 15 种不同的状态。
      • @Johan - 不,我不是,只是一个幸运的猜测。我试图展示的是两种不同的可能性。我展示了如何分别处理每个四位值并使用枚举作为一个值。
      猜你喜欢
      • 2021-01-06
      • 2013-07-10
      • 1970-01-01
      • 2018-08-27
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2020-07-15
      相关资源
      最近更新 更多