C#二进制文字


186

有没有办法用C#编写二进制文字,例如用0x前缀十六进制?0b不起作用。

如果没有,什么是简单的方法?某种字符串转换?


2
使用常量并为其指定适当的名称,那么不必用十进制写出来的事实就无关紧要了。我个人想读的if (a == MaskForModemIOEnabled)不是if (a == 0b100101)
Lasse V. Karlsen,2010年

1
另一注:如果您由于需要位字段而找到了此帖子,请考虑标志属性:msdn.microsoft.com/en-us/library/cc138362.aspx#sectionToggle0
toxvaerd 2010年

16
两种非常好的建议,除了定义所述位域时,在这些位域中,这些命名的常量定义可以使用二进制文字更容易读写。[标记]枚举数量{无= 0,一个= 1,一些= 0b10,大多数= 0b100,所有= 0b111}
brianary 2010年

1
出于价值考虑,计划为Roslyn支持二进制文字。
乔·怀特

C#6.0仍然不支持它,对吧?vs2015中不能使用二进制文字:/
anhoppe

Answers:


145

C#7.0支持二进制文字(以及下划线字符和可选的数字分隔符)。

一个例子:

int myValue = 0b0010_0110_0000_0011;

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


3
@ D.Singh我现在在C#7列表中看到它。github.com/dotnet/roslyn/issues/2136
日期

9
甜!在VS2017 / C#7中运行良好。
STLDev '17

1
记住C#的Binary Literal是大端的,而在x86整数上是小端的,因此Int16 = 0b0010_0110_0000_0011将其存储为{ 0b0000_0011, 0b0010_0110 }-容易混淆。

1
@Dai与十六进制文字没有什么不同。换句话说,所有常量都是big endian,但在Intel / AMD和大多数ARM上都存储了little endian。0xDEADBEEF将存储为0xEF 0xBE 0xAD 0xDE
Cole Johnson

168

更新资料

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
}

26
@ColeJohnson:许多开发人员都喜欢这样做。我不像某些开发人员那样擅长转换十六进制,有时最好迎合最低的公分母。
StriplingWarrior 2012年

2
我认为这是最有效的方法,因为枚举是作为常量构建的。通过可选的[Flags]属性,它们可以用于按位运算(与问题不直接相关,但是在描述二进制文字时特别有用)。另一个有趣的可能性是强制将枚举类型设置为内置类型(在此示例中,在“天”之后添加“:字节”);请参见bit.ly/MKv42E中的
caligari

实际上,这很容易阅读,尽管在Enum上声明0标志是相当不好的做法
MikeT 2015年

5
@MikeT:您能否详细说明(或提供详细说明的链接)?我经常声明以“ 1”开头的枚举,因为当一个值从未被初始化时,我希望能够检测并快速失败。但是在某些情况下,默认值实际上是有意义的,我认为为该值添加名称不会有任何问题。
StriplingWarrior

3
来自ca1008的@MikeT“如果应用了FlagsAttribute的枚举定义了零值成员,则其名称应为'None',以指示该枚举中未设置任何值。” 所以这是非常有效的将它添加到作为默认值,如果它被称为“无”。总体而言,如果默认初始化字段中的值实际上具有要显示的名称,对我来说似乎更干净。
Nyerguds

115

恐怕只能是整数和十六进制(ECMA 334v4):

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

要解析,您可以使用:

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

4
作为对此答案的更新,提供了最新的最新现代信息(2014年7月);C#6.0引入了二进制文字。底部看到我更新的答案wayyyyyy ...
BTownTKD 2014年

1
@BTownTKD您的答案实际上位于顶部:),因为它是公认的答案。
RBT

25

除了@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(移位)1-2-4-8(移位)...


为了回答原始问题,我第二次建议@Sahuagin使用十六进制文字。如果您经常使用二进制数来解决这个问题,那么花十六进制数是值得的。

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


23

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

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);


3
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位二进制文​​件,我使用它来创建一个静态类,并将其放入剪贴板。至少是静态的,但仍然...我在很多PIC图形编码中使用C#,而在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, 
}

:-)尼尔


3

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

我们可以使用一个或多个下划线(_)字符作为数字分隔符。因此,代码段如下所示:

int x           = 0b10___10_0__________________00; //binary value of 80
int SeventyFive = 0B100_________1011; //binary value of 75

WriteLine($" {x} \n {SeventyFive}");

并且我们可以使用0b和0B之一,如上面的代码片段所示。

如果您不想使用数字分隔符,则可以不使用数字分隔符来使用它,如下面的代码片段所示

int x           = 0b1010000; //binary value of 80
int SeventyFive = 0B1001011; //binary value of 75

WriteLine($" {x} \n {SeventyFive}");

2

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


BitConverter有点棘手,因为它是机器端的。在您的标准Intel上,这意味着低位优先。大多数人在阅读小尾数文字时有困难...
马克·格雷夫

1
哎呀,现在我记得为什么我一直都知道但从未使用过BitConverter ...
Michael Stum

4
BitConverter具有字段BitConverter.IsLittleEndian,如果主机计算机的字节序不低,则可以使用该字段进行测试(并反转缓冲区)。
狡猾的

1

尽管字符串解析解决方案是最受欢迎的解决方案,但我不喜欢它,因为在某些情况下解析字符串可能会大大降低性能。

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

长位掩码= 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;
    }
}

4
uck 为什么不只使用枚举?用千位表示1-0-0-0只是在麻烦。
克莱门特

1

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


0

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

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

这里的其他答案给出了一些有用的工作-回合,但我认为它们并不比简单的答案更好。C#语言设计人员可能认为不需要'0b'前缀。十六进制很容易转换为二进制,并且大多数程序员无论如何都必须知道0-8的DEC等效项。

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

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.