我可以在C或C ++中使用二进制文字吗?


190

我需要使用一个二进制数。

我试着写:

const x = 00010000;

但这没有用。

我知道我可以使用与值相同的十六进制数00010000,但是我想知道C ++中是否存在用于二进制数的类型,如果没有,那么是否存在针对我的问题的另一种解决方案?


51
你知道那00010000是八进制的,对吗?(而且您的声明缺少类型。)
Keith Thompson

这是使用C ++文字的现代方式。
Lol4t0

2
C ++ 14为此添加了一个功能。请在底部查看我的新答案以获取更多详细信息。当然,它确实需要实现它的编译器。
lpapp

1
@FormlessCloud:这些是C和C ++标准中给出的语法规则(0b仅在C ++ 14中出现)。它们的设计是明确的。
基思·汤普森

Answers:


70

您可以使用BOOST_BINARY在等待的C ++ 0x。:) BOOST_BINARY可以说与模板实现相比具有优势,因为它也可以在C程序中使用(它是100%预处理器驱动的。)

要进行相反的处理(即以二进制形式打印数字),可以使用非便携式itoa函数,也可以实现自己的

不幸的是,您不能使用STL流进行base 2格式化(因为setbase将仅支持base 8、10和16),但是您可以使用或的std::string版本itoa(更为简洁,但效率稍低)std::bitset

#include <boost/utility/binary.hpp>
#include <stdio.h>
#include <stdlib.h>
#include <bitset>
#include <iostream>
#include <iomanip>

using namespace std;

int main() {
  unsigned short b = BOOST_BINARY( 10010 );
  char buf[sizeof(b)*8+1];
  printf("hex: %04x, dec: %u, oct: %06o, bin: %16s\n", b, b, b, itoa(b, buf, 2));
  cout << setfill('0') <<
    "hex: " << hex << setw(4) << b << ", " <<
    "dec: " << dec << b << ", " <<
    "oct: " << oct << setw(6) << b << ", " <<
    "bin: " << bitset< 16 >(b) << endl;
  return 0;
}

产生:

hex: 0012, dec: 18, oct: 000022, bin:            10010
hex: 0012, dec: 18, oct: 000022, bin: 0000000000010010

另请阅读Herb Sutter的“庄园农场的弦乐格式化者”,以进行有趣的讨论。


2
就像您链接到的页面所说,您只能将8、10或16与setbase一起使用。但是:int main() { cout << bitset<8>(42); }

@Roger感谢您的bitset提示,setbase不过在看到您的评论之前,我已经纠正了一些问题。
vladr

这是有关c ++ 11中用户定义文字的教程:akrzemi1.wordpress.com/2012/10/23/user-defined-literals-part-ii。显然,c ++ 1y(也称为c ++ 14)将在标准中包含二进制文字。
cheshirekow

274

如果您使用的是GCC,则可以为此使用GCC扩展(包含在C ++ 14标准中):

int x = 0b00010000;

2
其他一些编译器有这个或其他类似的以2为底数表达数字的方式
nategoose

4
对此进行标准化会很好,但是clang支持相同的表示法。
polemon

14
它适用于Clang,GCC和TCC。它在PCC中不起作用。我没有其他可以测试的编译器。
Michas 2011年

6
我已经看到了许多支持它的嵌入式系统编译器。我不知道它不应该成为标准语言功能的任何特殊原因。
supercat


98

您可以使用二进制文字。它们在C ++ 14中标准化。例如,

int x = 0b11000;

在GCC中的支持

GCC中的支持始于GCC 4.3(请参阅https://gcc.gnu.org/gcc-4.3/changes.html),作为对C语言家族的扩展(请参阅https://gcc.gnu.org/onlinedocs/gcc/ C-Extensions.html#C-Extensions),但是自GCC 4.9起,它现在被视为C ++ 14功能或扩展名(请参阅GCC二进制文字和C ++ 14的区别?

Visual Studio中的支持

在Visual Studio 2015预览版中开始了对Visual Studio的支持(请参阅https://www.visualstudio.com/news/vs2015-preview-vs#C++)。


5
您可以使用'分隔每个部分:“ 0b0000'0100'0100'0001
camino

1
@camino尼斯,您可以放宽第一个
Nikos

这应该是公认的答案。其他大多数答案都过时了。
亚历克斯

73
template<unsigned long N>
struct bin {
    enum { value = (N%10)+2*bin<N/10>::value };
} ;

template<>
struct bin<0> {
    enum { value = 0 };
} ;

// ...
    std::cout << bin<1000>::value << '\n';

文字的最左位数仍必须为1,但仍然如此。


4
更好的版本:bitbucket.org/kniht/scraps/src/tip/cpp/binary.hppbinary<10>::value == binary<010>::value以及一些错误检查)

在我发布自己几乎相同的答案之前,不知何故错过了这个答案。但在我前面的数字必须是0,而不是1
马克赎金


@ValentinGalea-为什么Google版本比这个更好?
2016年

这真令人印象深刻。太糟糕了,它对于大量的位不起作用。
量子物理学家

31

少数编译器(通常是微控制器的编译器)具有特殊功能,即在数字二进制数字之前通过前缀数字“ 0b ...”来识别文字二进制数,尽管大多数编译器(C / C ++标准)不具有这种功能,如果是这种情况,这是我的替代解决方案:

#define B_0000    0
#define B_0001    1
#define B_0010    2
#define B_0011    3
#define B_0100    4
#define B_0101    5
#define B_0110    6
#define B_0111    7
#define B_1000    8
#define B_1001    9
#define B_1010    a
#define B_1011    b
#define B_1100    c
#define B_1101    d
#define B_1110    e
#define B_1111    f

#define _B2H(bits)    B_##bits
#define B2H(bits)    _B2H(bits)
#define _HEX(n)        0x##n
#define HEX(n)        _HEX(n)
#define _CCAT(a,b)    a##b
#define CCAT(a,b)   _CCAT(a,b)

#define BYTE(a,b)        HEX( CCAT(B2H(a),B2H(b)) )
#define WORD(a,b,c,d)    HEX( CCAT(CCAT(B2H(a),B2H(b)),CCAT(B2H(c),B2H(d))) )
#define DWORD(a,b,c,d,e,f,g,h)    HEX( CCAT(CCAT(CCAT(B2H(a),B2H(b)),CCAT(B2H(c),B2H(d))),CCAT(CCAT(B2H(e),B2H(f)),CCAT(B2H(g),B2H(h)))) )

// Using example
char b = BYTE(0100,0001); // Equivalent to b = 65; or b = 'A'; or b = 0x41;
unsigned int w = WORD(1101,1111,0100,0011); // Equivalent to w = 57155; or w = 0xdf43;
unsigned long int dw = DWORD(1101,1111,0100,0011,1111,1101,0010,1000); //Equivalent to dw = 3745774888; or dw = 0xdf43fd28;

缺点(不是很大):

  • 二进制数必须按4 4分组。
  • 二进制文字只能是无符号整数。

优点

  • 总的预处理器驱动,而不是对可执行程序spending processor time进行无意义的操作(like "?.. :..", "<<", "+")(在最终应用程序中可能执行数百次);
  • 它也适用于"mainly in C"编译器和C ++(template+enum solution works only in C++ compilers);
  • 在表达“文字常数”值时,它仅具有“长度”的限制。如果有人通过解析"enum solution" (usually 255 = reach enum definition limit)“ literal constant”限制的解析度来表达常数值,则可能会出现早期的长度限制(通常为8位:0-255),而在编译器中允许使用更大的数字;
  • 其他一些解决方案则需要大量的常量定义(在我看来,定义太多了),包括冗长的several header files(或在大多数情况下不容易阅读和理解),并且使项目变得不必要的混乱和扩展,例如使用"BOOST_BINARY()");
  • 解决方案的简单性:在其他情况下易于阅读,易于理解和可调(也可以扩展为将8乘8分组);

为什么B_0100不使用例如(而不是0100)?如在char b = BYTE(0100,0001);
Peter Mortensen17年

@PeterMortensen B_由_B2H预处理器函数添加。
mxmlnkn

20

该线程可能会有所帮助。

/* Helper macros */
#define HEX__(n) 0x##n##LU
#define B8__(x) ((x&0x0000000FLU)?1:0) \
+((x&0x000000F0LU)?2:0) \
+((x&0x00000F00LU)?4:0) \
+((x&0x0000F000LU)?8:0) \
+((x&0x000F0000LU)?16:0) \
+((x&0x00F00000LU)?32:0) \
+((x&0x0F000000LU)?64:0) \
+((x&0xF0000000LU)?128:0)

/* User macros */
#define B8(d) ((unsigned char)B8__(HEX__(d)))
#define B16(dmsb,dlsb) (((unsigned short)B8(dmsb)<<8) \
+ B8(dlsb))
#define B32(dmsb,db2,db3,dlsb) (((unsigned long)B8(dmsb)<<24) \
+ ((unsigned long)B8(db2)<<16) \
+ ((unsigned long)B8(db3)<<8) \
+ B8(dlsb))


#include <stdio.h>

int main(void)
{
    // 261, evaluated at compile-time
    unsigned const number = B16(00000001,00000101);

    printf("%d \n", number);
    return 0;
}

有用!(所有学分归汤姆·托夫斯所有。)


我不是很了解(ima是编程方面的初学者,特别是C ++的初学者),但似乎很有趣,所以我将在进行了一些C ++学习之后尝试理解它,谢谢
hamza 2010年

3
B8宏通过将“二进制”文字转换为十六进制文字并提取第4位来工作。
dan04

我想知道0x ## n ## LU是什么意思?从未遇到过这样的语法。
Federico A. Ramponi 2010年

@hamza:的确确实很复杂。但是您只需要从#include <stdio>开始就可以理解。
Federico A. Ramponi 2010年

8
@Federico:##预处理程序运算符将令牌粘贴在一起。因此,在这种情况下,如果您调用HEX__(10),它将扩展为0x10LU
James McNellis

18

正如已经回答的那样,C标准无法直接写入二进制数字。但是,有编译器扩展,显然C ++ 14包含0b二进制前缀。(请注意,此答案最初于2010年发布。)

一种流行的解决方法是包括带有帮助程序宏的头文件。一个简单的选择就是生成一个包含所有8位模式宏定义的文件,例如:

#define B00000000 0
#define B00000001 1
#define B00000010 2

这仅需256 #defines,并且如果需要大于8位的二进制常量,则可以将这些定义与shift和OR结合使用,可能还可以与辅助宏(例如BIN16(B00000001,B00001010))结合使用。(对于每个16位,更不用说32位,都有单独的宏,值似乎不合理。)

当然,缺点是此语法要求写入所有前导零,但这对于使用诸如设置位标志和硬件寄存器的内容之类的用途来说也可能更清楚。有关导致没有此属性的语法的类函数宏,请参见bithacks.h上面的链接。


2
那么,如果您拥有的所有宏,CPP需要读取多大的文件long long int
wilhelmtell

3
@wilhelmtell:当我指定“所有8位模式”(= 256行)并建议合并其中的更大数量时,这有什么意义?即使是接受答案的BOOST_BINARY也定义了标头中的所有8位模式…
Arkku

16

在这里的其他答案中,已经很好地说明了C ++过度设计的心态。这是我使用C,keep-it-simple-ffs心态进行的尝试:

unsigned char x = 0xF; // binary: 00001111


11

您可以使用此问题中找到的函数在C ++中最多获取22位。这是链接中经过适当编辑的代码:

template< unsigned long long N >
struct binary
{
  enum { value = (N % 8) + 2 * binary< N / 8 > :: value } ;
};

template<>
struct binary< 0 >
{
  enum { value = 0 } ;
};

所以你可以做类似的事情binary<0101011011>::value


7

您可以使用的最小单位是一个字节(char类型)。尽管可以使用按位运算符来处理位。

对于整数文字,只能使用十进制(以10为底),八进制(以8为底)或十六进制(以16为底)数字。C和C ++中都没有二进制(以2为基)的文字。

八进制数字以开头,0十六进制数字以开头0x。十进制数没有前缀。

在C ++ 0x中,您可以通过用户定义的文字来做您想做的事情。


我至少可以在打印或cout函数中显示十六进制的Binary值吗?
hamza 2010年

是的,您可以<shameless_plug> stackoverflow.com/questions/2611764#2611883 </shameless_plug>
vladr

5
一些C编译器支持二进制文字为0b100101,但是不幸的是,它是非标准扩展。
乔伊·亚当斯

3
请注意,尽管标准中未对其进行定义,但是一些编译器(尤其是用于微控制器和嵌入式系统的编译器)0b00101010为方便起见以二进制形式添加了二进制语法。SDCC是其中之一,我敢肯定还有其他公司也可以这样做。(编辑:哈,打败我,@ Joey!)
Matt B. 2010年

5

您也可以像这样使用内联汇编:

int i;

__asm {
    mov eax, 00000000000000000000000000000000b
    mov i,   eax
}

std::cout << i;

好的,可能有点过大了,但是可以。


3
您的解决方案不是多平台的。在许多体系结构中,您不能在C中包括汇编代码。特别是在Microsoft Visual Studio编译器中,可以(在为x86 32位编译时)。但是,您怎么甚至知道处理器是否具有“ eax”寄存器?想一想手机中的ARM处理器,x64处理器等。它们没有“ eax”。MIPS处理器甚至没有命令“MOV”
DanielHsH

4

根据其他答案,但是此答案将拒绝带有非法二进制文字的程序。前导零是可选的。

template<bool> struct BinaryLiteralDigit;

template<> struct BinaryLiteralDigit<true> {
    static bool const value = true;
};

template<unsigned long long int OCT, unsigned long long int HEX>
struct BinaryLiteral {
    enum {
        value = (BinaryLiteralDigit<(OCT%8 < 2)>::value && BinaryLiteralDigit<(HEX >= 0)>::value
            ? (OCT%8) + (BinaryLiteral<OCT/8, 0>::value << 1)
            : -1)
    };
};

template<>
struct BinaryLiteral<0, 0> {
    enum {
        value = 0
    };
};

#define BINARY_LITERAL(n) BinaryLiteral<0##n##LU, 0x##n##LU>::value

例:

#define B BINARY_LITERAL

#define COMPILE_ERRORS 0

int main (int argc, char ** argv) {
    int _0s[] = { 0, B(0), B(00), B(000) };
    int _1s[] = { 1, B(1), B(01), B(001) };
    int _2s[] = { 2, B(10), B(010), B(0010) };
    int _3s[] = { 3, B(11), B(011), B(0011) };
    int _4s[] = { 4, B(100), B(0100), B(00100) };

    int neg8s[] = { -8, -B(1000) };

#if COMPILE_ERRORS
    int errors[] = { B(-1), B(2), B(9), B(1234567) };
#endif

    return 0;
}

3

二进制数的“类型”与任何十进制,十六进制或八进制数字相同: int甚至是char,short,long long)。

分配常数时,不能用11011011分配它(奇怪和不幸的是),但是可以使用十六进制。十六进制在思维上更容易翻译。切块(4位),并转换为[0-9a-f]中的字符。


2

您可以使用位集

bitset<8> b(string("00010000"));
int i = (int)(bs.to_ulong());
cout<<i;

2

我通过确保以下人员的支持来扩展@ renato-chandelier提供的良好答案:

  • _NIBBLE_(…) – 4位,1个半字节作为参数
  • _BYTE_(…) – 8位,2个半字节作为参数
  • _SLAB_(…) – 12位,3个半字节作为参数
  • _WORD_(…) – 16位,4个半字节作为参数
  • _QUINTIBBLE_(…) – 20位,5个半字节作为参数
  • _DSLAB_(…) – 24位,6个半字节作为参数
  • _SEPTIBBLE_(…) – 28位,7个半字节作为参数
  • _DWORD_(…) – 32位,8个半字节作为参数

我实际上对“ quintibble”和“ septibble”这两个术语不太确定。如果有人知道其他选择,请告诉我。

这是重写的宏:

#define __CAT__(A, B) A##B
#define _CAT_(A, B) __CAT__(A, B)

#define __HEX_0000 0
#define __HEX_0001 1
#define __HEX_0010 2
#define __HEX_0011 3
#define __HEX_0100 4
#define __HEX_0101 5
#define __HEX_0110 6
#define __HEX_0111 7
#define __HEX_1000 8
#define __HEX_1001 9
#define __HEX_1010 a
#define __HEX_1011 b
#define __HEX_1100 c
#define __HEX_1101 d
#define __HEX_1110 e
#define __HEX_1111 f

#define _NIBBLE_(N1) _CAT_(0x, _CAT_(__HEX_, N1))
#define _BYTE_(N1, N2) _CAT_(_NIBBLE_(N1), _CAT_(__HEX_, N2))
#define _SLAB_(N1, N2, N3) _CAT_(_BYTE_(N1, N2), _CAT_(__HEX_, N3))
#define _WORD_(N1, N2, N3, N4) _CAT_(_SLAB_(N1, N2, N3), _CAT_(__HEX_, N4))
#define _QUINTIBBLE_(N1, N2, N3, N4, N5) _CAT_(_WORD_(N1, N2, N3, N4), _CAT_(__HEX_, N5))
#define _DSLAB_(N1, N2, N3, N4, N5, N6) _CAT_(_QUINTIBBLE_(N1, N2, N3, N4, N5), _CAT_(__HEX_, N6))
#define _SEPTIBBLE_(N1, N2, N3, N4, N5, N6, N7) _CAT_(_DSLAB_(N1, N2, N3, N4, N5, N6), _CAT_(__HEX_, N7))
#define _DWORD_(N1, N2, N3, N4, N5, N6, N7, N8) _CAT_(_SEPTIBBLE_(N1, N2, N3, N4, N5, N6, N7), _CAT_(__HEX_, N8))

这是Renato的使用示例:

char b = _BYTE_(0100, 0001); /* equivalent to b = 65; or b = 'A'; or b = 0x41; */
unsigned int w = _WORD_(1101, 1111, 0100, 0011); /* equivalent to w = 57155; or w = 0xdf43; */
unsigned long int dw = _DWORD_(1101, 1111, 0100, 0011, 1111, 1101, 0010, 1000); /* Equivalent to dw = 3745774888; or dw = 0xdf43fd28; */

0

只需使用C ++中的标准库即可:

#include <bitset>

您需要一个类型变量std::bitset

std::bitset<8ul> x;
x = std::bitset<8>(10);
for (int i = x.size() - 1; i >= 0; i--) {
      std::cout << x[i];
}

在此示例中,我存储了10in 的二进制形式x

8ul定义您的位的大小,因此7ul意味着七个位,依此类推。



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.