【问题标题】:C# binary literalsC# 二进制字面量
【发布时间】:2010-10-10 07:58:00
【问题描述】:

有没有办法在 C# 中编写二进制文字,比如在十六进制前面加上 0x? 0b 不起作用。

如果没有,有什么简单的方法可以做到这一点?某种字符串转换?

【问题讨论】:

  • 使用常量并给它们正确的名字,那么你必须用十进制写出它们的事实应该无关紧要。就我个人而言,我想阅读 if (a == MaskForModemIOEnabled) 而不是 if (a == 0b100101)
  • 另外注意:如果你发现这篇文章是因为你想要一个位字段,请考虑flags-attribute:msdn.microsoft.com/en-us/library/cc138362.aspx#sectionToggle0
  • 两个非常好的建议,除了当 defining 表示位域时,这些命名的常量定义可以更容易地用二进制文字进行读写。 [标志]枚举数量 { None=0, One=1, Some=0b10, Most=0b100, All=0b111 }
  • 无论如何,支持二进制文字is planned for Roslyn
  • C#6.0 仍然不支持它,对吧?不能在 vs2015 中使用二进制文字:/

标签: c# syntax binary


【解决方案1】:

恐怕只能直接使用整数和十六进制(ECMA 334v4):

9.4.4.2 整数字面量 整数字面量用于写入 类型 int、uint、long 和 ulong。 整数文字有两种可能 形式:十进制和十六进制。

要解析,可以使用:

int i = Convert.ToInt32("01101101", 2);

【讨论】:

  • 作为此答案的更新,带有最新的尖端现代信息(2014 年 7 月); C# 6.0 引入了二进制文字。在底部查看我的更新答案 wayyyyyy ...
  • @BTownTKD 你的答案实际上在顶部 :) 因为它是公认的答案。
【解决方案2】:

虽然无法使用 Literal,但也许 BitConverter 也可以作为解决方案?

【讨论】:

  • BitConverter 有点棘手,因为它是机器端;在您的标准英特尔上,这意味着小端。大多数人在阅读小端文字时有困难......
  • 哎呀,现在我记得为什么我一直知道但从未使用过 BitConverter...
  • BitConverter 有字段BitConverter.IsLittleEndian,如果主机不是小端序,您可以使用它来测试(并反转缓冲区)。
【解决方案3】:

您始终可以创建包含您所追求的值的准字面量常量:

const int b001 = 1;
const int b010 = 2;
const int b011 = 3;
// etc ...
Debug.Assert((b001 | b010) == b011);

如果您经常使用它们,那么您可以将它们包装在一个静态类中以供重复使用。

但是,稍微偏离主题,如果您有任何与位相关的语义(在编译时已知),我建议您改用 Enum:

enum Flags
{ 
    First = 0,
    Second = 1,
    Third = 2,
    SecondAndThird = 3
}
// later ...
Debug.Assert((Flags.Second | Flags.Third) == Flags.SecondAndThird);

【讨论】:

    【解决方案4】:

    虽然字符串解析解决方案是最流行的,但我不喜欢它,因为在某些情况下解析字符串可能会对性能产生很大影响。

    当需要某种位域或二进制掩码时,我宁愿这样写

    长位掩码 = 1011001;

    后来

    int bit5 = BitField.GetBit(bitMask, 5);

    或者

    bool flag5 = BitField.GetFlag(bitMask, 5);`

    BitField 类在哪里

    public static class BitField
    {
        public static int GetBit(int bitField, int index)
        {
            return (bitField / (int)Math.Pow(10, index)) % 10;
        }
    
        public static bool GetFlag(int bitField, int index)
        {
            return GetBit(bitField, index) == 1;
        }
    }
    

    【讨论】:

    • 呸。为什么不只使用枚举?用 1-0-0-0 表示 1-0-0-0 只是自找麻烦。
    【解决方案5】:

    更新

    C# 7.0 现在有了二进制字面量,这太棒了。

    [Flags]
    enum Days
    {
        None = 0,
        Sunday    = 0b0000001,
        Monday    = 0b0000010,   // 2
        Tuesday   = 0b0000100,   // 4
        Wednesday = 0b0001000,   // 8
        Thursday  = 0b0010000,   // 16
        Friday    = 0b0100000,   // etc.
        Saturday  = 0b1000000,
        Weekend = Saturday | Sunday,
        Weekdays = Monday | Tuesday | Wednesday | Thursday | Friday
    }
    

    原帖

    由于话题似乎已经转向在枚举中声明基于位的标志值,我认为有必要为这类事情指出一个方便的技巧。左移运算符 (<<) 将允许您将位推到特定的二进制位置。将它与根据同一类中的其他值声明枚举值的能力相结合,您就有了一个非常易于阅读的位标志枚举的声明性语法。

    [Flags]
    enum Days
    {
        None        = 0,
        Sunday      = 1,
        Monday      = 1 << 1,   // 2
        Tuesday     = 1 << 2,   // 4
        Wednesday   = 1 << 3,   // 8
        Thursday    = 1 << 4,   // 16
        Friday      = 1 << 5,   // etc.
        Saturday    = 1 << 6,
        Weekend     = Saturday | Sunday,
        Weekdays    = Monday | Tuesday | Wednesday | Thursday | Friday
    }
    

    【讨论】:

    • @ColeJohnson:许多开发人员更喜欢这样。我不像某些开发人员那样擅长在脑海中转换十六进制,有时最好迎合最低公分母。
    • 我认为这是最有效的方法,因为枚举是作为常量构建的。使用可选的 [Flags] 属性,它们可以用于按位运算(与问题没有直接关系,但在描述二进制文字时特别有用)。另一个有趣的可能性是将枚举类型强制为内置类型(在此示例中,在 'Days' 之后添加' : byte');查看bit.ly/MKv42E中的内置类型
    • 这实际上很容易阅读,尽管在 Enum 上声明 0 标志是相当糟糕的做法
    • @MikeT:您能否详细说明(或提供详细说明的链接)最后的想法?我经常声明以“1”开头的枚举,因为我希望能够detect and fail-fast 当一个值根本没有初始化时。但是在某些情况下,默认值实际上是有意义的,我认为为该值添加名称不会有任何问题。
    • @MikeT From ca1008: "如果一个应用了 FlagsAttribute 的枚举定义了一个零值成员,它的名字应该是 'None' 表示没有设置任何值枚举。” 所以添加它作为默认值是完全有效的,如果它被称为“无”。总的来说,如果默认初始化字段中的值实际上有一个要显示的名称,对我来说似乎更清晰。
    【解决方案6】:
    string sTable="static class BinaryTable\r\n{";
    string stemp = "";
    for (int i = 0; i < 256; i++)
    {
    stemp = System.Convert.ToString(i, 2);
    while(stemp.Length<8) stemp = "0" + stemp;
    sTable += "\tconst char nb" + stemp + "=" + i.ToString() + ";\r\n";
    }
    sTable += "}";
    Clipboard.Clear();
    Clipboard.SetText ( sTable);
    MessageBox.Show(sTable);
    

    使用它,对于 8 位二进制文​​件,我使用它来创建一个静态类并将其放入剪贴板中。然后将其粘贴到项目中并添加到使用部分,因此任何带有 nb001010 的内容都会从表,至少是静态的,但仍然...... 我使用 C# 进行大量 PIC 图形编码,并在 Hi-Tech C 中大量使用 0b101010

    --代码输出示例--

    static class BinaryTable
    {   const char nb00000000=0;
        const char nb00000001=1;
        const char nb00000010=2;
        const char nb00000011=3;
        const char nb00000100=4;
    //etc, etc, etc, etc, etc, etc, etc, 
    }
    

    :-) 尼尔

    【讨论】:

      【解决方案7】:

      除了@StriplingWarrior 关于枚举中的位标志的回答之外,还有一个简单的约定,您可以使用十六进制来通过位移位向上计数。使用序列 1-2-4-8,向左移动一列,然后重复。

      [Flags]
      enum Scenery
      {
        Trees   = 0x001, // 000000000001
        Grass   = 0x002, // 000000000010
        Flowers = 0x004, // 000000000100
        Cactus  = 0x008, // 000000001000
        Birds   = 0x010, // 000000010000
        Bushes  = 0x020, // 000000100000
        Shrubs  = 0x040, // 000001000000
        Trails  = 0x080, // 000010000000
        Ferns   = 0x100, // 000100000000
        Rocks   = 0x200, // 001000000000
        Animals = 0x400, // 010000000000
        Moss    = 0x800, // 100000000000
      }
      

      从右栏开始向下扫描,注意模式 1-2-4-8 (shift) 1-2-4-8 (shift) ...


      为了回答最初的问题,我赞同@Sahuagin 使用十六进制文字的建议。如果您经常使用二进制数来担心这一点,那么值得您花时间掌握十六进制的窍门。

      如果您需要在源代码中查看二进制数,我建议像上面那样添加带有二进制文字的 cmets。

      【讨论】:

        【解决方案8】:

        基本上,我认为答案是否定的,没有简单的方法。使用十进制或十六进制常量——它们简单明了。 @RoyTinkers 的回答也不错 - 使用评论。

        int someHexFlag = 0x010; // 000000010000
        int someDecFlag = 8;     // 000000001000
        

        这里的其他答案提供了几个有用的工作-一轮,但我认为它们并不比简单的答案更好。 C# 语言设计者可能认为不需要“0b”前缀。 HEX 很容易转换为二进制,大多数程序员无论如何都必须知道 0-8 的 DEC 等价物。

        此外,在调试器中检查值时,它们将显示为 HEX 或 DEC。

        【讨论】:

          【解决方案9】:

          如果您查看 .NET 编译器平台(“Roslyn”)的language feature implementation status,您可以清楚地看到在 C# 6.0 中这是一个计划中的功能,因此在下一个版本中我们可以按照通常的方式进行。

          【讨论】:

          【解决方案10】:

          C# 7.0 支持 binary literals(以及可选的下划线数字分隔符)。

          一个例子:

          int myValue = 0b0010_0110_0000_0011;
          

          您还可以在Roslyn GitHub page 上找到更多信息。

          【讨论】:

          • @D.Singh 我现在在 C# 7 列表中看到它。 github.com/dotnet/roslyn/issues/2136
          • 甜蜜!在 VS2017 / C#7 中工作得很好。
          • 记住 C# 的二进制文字是大端序的,但在 x86 上整数是小端序的,所以 Int16 = 0b0010_0110_0000_0011 将存储为 { 0b0000_0011, 0b0010_0110 } - 令人困惑。
          • @Dai 这与十六进制文字没有什么不同。换句话说,所有常量都是大端,但在 Intel/AMD 和大多数 ARM 上存储的是小端。 0xDEADBEEF 将存储为 0xEF 0xBE 0xAD 0xDE
          【解决方案11】:

          二进制文字功能未在 C# 6.0 和 Visual Studio 2015 中实现。但在 2016 年 3 月 30 日,Microsoft 宣布了新版本的 Visual Studio '15' Preview,我们可以使用二进制文字。

          我们可以使用一个或多个下划线(_)字符作为数字分隔符。所以代码 sn-p 看起来像:

          int x           = 0b10___10_0__________________00; //binary value of 80
          int SeventyFive = 0B100_________1011; //binary value of 75
          
          WriteLine($" {x} \n {SeventyFive}");
          

          我们可以使用 0b 和 0B 中的任何一个,如上面的代码 sn-p 所示。

          如果你不想使用数字分隔符,你可以不使用数字分隔符,如下面的代码 sn-p

          int x           = 0b1010000; //binary value of 80
          int SeventyFive = 0B1001011; //binary value of 75
          
          WriteLine($" {x} \n {SeventyFive}");
          

          【讨论】:

            【解决方案12】:

            自 Visual Studio 2017 (C# 7.0) 起,您可以使用 0b000001

            【讨论】:

              猜你喜欢
              • 2022-01-25
              • 2010-10-16
              • 1970-01-01
              • 2010-10-06
              • 2020-01-10
              • 2010-11-17
              • 1970-01-01
              • 1970-01-01
              • 2015-05-26
              相关资源
              最近更新 更多