【问题标题】:Can I use a binary literal in C or C++?我可以在 C 或 C++ 中使用二进制文字吗?
【发布时间】:2011-02-06 09:26:44
【问题描述】:

我需要使用二进制数。

我试着写了:

const x = 00010000;

但它没有用。

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

【问题讨论】:

  • 你知道00010000 是八进制的,对吧? (而且您的声明缺少类型。)
  • Here 使用 C++ 文字的现代方式。
  • C++14 为此添加了一项功能。请参阅我的新答案以获取底部的更多详细信息。当然,它确实需要一个实现它的编译器。
  • @FormlessCloud:这些是 C 和 C++ 标准中给出的语法规则(0b 仅出现在 C++14 中)。它们的设计目的是明确的。
  • Binary literals?的可能重复

标签: c++ c binary


【解决方案1】:

如果您使用的是 GCC,那么您可以为此使用 a GCC extension(包含在 the C++14 standard 中):

int x = 0b00010000;

【讨论】:

  • 其他几个编译器有这种或其他类似的方式来表达以 2 为底的数字。
  • 如果能把这个标准化就好了,但 clang 支持相同的表示法。
  • 它适用于 Clang、GCC 和 TCC。它在 PCC 中不起作用。我没有任何其他编译器可以测试。
  • 我见过很多支持它的嵌入式系统编译器。我不知道它不应该成为标准语言功能的任何特殊原因。
【解决方案2】:

您可以使用二进制文字。它们在 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 功能或扩展(见Difference between GCC binary literals and C++14 ones?)

Visual Studio 中的支持

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

【讨论】:

  • 您可以使用'分隔各个部分:"0b0000'0100'0100'0001
  • @camino 很高兴你可以放弃第一个“
  • 这应该是公认的答案。大多数其他答案都已经过时了。
【解决方案3】:
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,但仍然如此。

【讨论】:

  • 更好的版本:bitbucket.org/kniht/scraps/src/tip/cpp/binary.hppbinary&lt;10&gt;::value == binary&lt;010&gt;::value 和一些错误检查)
  • 在我发布自己几乎相同的答案之前,不知何故错过了这个。但在我的第一个数字必须是 0,而不是 1。
  • 这个模板想法的更好版本:code.google.com/p/cpp-binary-constants
  • @ValentinGalea - 为什么 google 版本比这更好?
  • 这真是令人印象深刻。太糟糕了,它不适用于高位数。
【解决方案4】:

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

要反过来(即打印出二进制形式的数字),您可以使用不可移植的itoa functionimplement your own

不幸的是,您不能使用 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 的 The String Formatters of Manor Farm 进行有趣的讨论。

【讨论】:

  • 正如您链接到的页面所说,您只能将 8、10 或 16 与 setbase 一起使用。但是:int main() { cout &lt;&lt; bitset&lt;8&gt;(42); }
  • @Roger 感谢bitset 的提示,不过在我看到你的评论之前,我已经更正了关于setbase 的问题。
  • 这是一个关于 c++11 中用户定义文字的教程:akrzemi1.wordpress.com/2012/10/23/user-defined-literals-part-ii。显然 c++1y (a.k.a. c++14) 将在标准中包含二进制文字。
【解决方案5】:

一些编译器(通常是 microcontrollers 的编译器)在通过数字前的 前缀“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 x 4 分组;
  • 二进制文字只能是无符号整数;

优势

  • 整个预处理器驱动,而不是 spending processor time 对可执行程序的无意义操作 (like "?.. :..", "&lt;&lt;", "+")(它可能在最终应用程序中执行数百次);
  • 它也适用于 "mainly in C" 编译器和 C++ (template+enum solution works only in C++ compilers);
  • 对于表达“字面常量”值,它只有“长度”的限制。如果通过解析 "enum solution" (usually 255 = reach enum definition limit) 的解析来表示常量值,则会有早期的长度限制(通常是 8 位:0-255),不同的是,编译器中的“字面常量”限制允许更大的数字;
  • 其他一些解决方案需要夸大数量的常量定义(我认为定义太多),包括 long 或 several header files(在大多数情况下不容易阅读和理解,并使项目变得不必要的混乱和扩展,就像使用 @ 987654329@);
  • 解决方案的简单性:对于其他情况,易于阅读、理解和调整(也可以扩展为 8 x 8 分组);

【讨论】:

  • 为什么是例如B_0100 未使用(而不是 0100)?如在例如char b = BYTE(0100,0001);.
  • @PeterMortensen B_ 由_B2H 预处理器函数添加。
【解决方案6】:

This thread 可能会有所帮助。

/* 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;
}

有效! (所有的功劳归于 Tom Torfs。)

【讨论】:

  • 我不太明白(我是编程初学者,特别是 C++),但它看起来很有趣,所以我会在更多 C++ 学习后尝试理解它,谢谢
  • B8 宏通过将“二进制”文字转换为十六进制文字并提取每 4 位来工作。
  • 我想知道 0x##n##LU 是什么意思?从来没有遇到过这样的语法。
  • @hamza:确实相当复杂。但是您需要了解的只是从#include 开始。
  • @Federico:## 预处理器运算符将标记粘贴在一起。所以,在这种情况下,如果你调用HEX__(10),它会扩展为0x10LU
【解决方案7】:

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

一种流行的解决方法是包含a header file with helper macros。一个简单的选择是生成一个包含所有 8 位模式的宏定义的文件,例如:

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

这将导致只有 256 个#defines,如果需要大于 8 位的二进制常量,这些定义可以与移位和 OR 结合,可能与辅助宏(例如,BIN16(B00000001,B00001010))结合使用。 (每个 16 位都有单独的宏,更不用说 32 位了,值是不合理的。)

当然,缺点是这种语法需要写入所有前导零,但这也可以使其更清楚地用于设置位标志和硬件寄存器的内容等用途。对于导致语法没有此属性的类似函数的宏,请参阅上面链接的bithacks.h

【讨论】:

  • 那么,如果您拥有 long long int 的所有宏,CPP 需要读取多大的文件?
  • @wilhelmtell:当我指定“所有 8 位 模式”(= 256 行)并建议从这些模式中组合更大数量时,这有什么相关性?甚至接受答案的 BOOST_BINARY 也定义了标头中的所有 8 位模式……
  • 不确定是赞成还是反对。一方面它很聪明,因为在编译之前完成了简单的文本替换。您可以简单地编写一个生成器来为大于 8 位的数据类型创建这样的头文件。另一方面,我不知道预处理器可以处理多少#define,也不知道它们是否可以有效处理。也许可以通过使用辅助宏与## 连接来减少必要定义的数量。
  • @tangoal 正如我在回答中所说,我建议仅对 8 位宏执行此操作,并且我明确声明我认为 16 位或更高版本不可行,我确实这样做了还建议将更高的宽度(超过 8 位)与辅助宏结合起来。因此,如果您投反对票,我希望原因与旧的“没有阅读答案,但这不适用于超过 8 位”不同,因为它不是故意的。 =)
  • 至于与## 的连接,我认为这需要像BIN16(0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1) 这样的语法,我认为这对答案中建议的BIN16(B00000001,B00001010) 没有太大的改进。或者除了这些基本形式之一,您还有其他想法吗? (诚​​然,具有智能自动补全功能的编辑器可能有助于使用前一种语法,并使用占位符放置正确数量的参数,这可以看作是一种改进,即使当你必须数到 16 时手动输入并不是那么好。 )
【解决方案8】:

这里的其他答案已经很好地说明了 C++ 过度工程的心态。这是我尝试用 C 语言保持简单 ffs 的心态:

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

【讨论】:

    【解决方案9】:

    C 没有纯二进制数的 native 表示法。您最好的选择是八进制(例如07777)或十六进制(例如0xfff)。

    【讨论】:

      【解决方案10】:

      您可以使用找到的函数in this question 在 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&lt;0101011011&gt;::value的事情。

      【讨论】:

        【解决方案11】:

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

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

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

        在 C++0x 中,你可以通过user defined literals 做你想做的事。

        【讨论】:

        • 我至少可以在 print 或 cout 函数中显示十六进制的二进制值吗?
        • 是的,你可以&lt;shameless_plug&gt; stackoverflow.com/questions/2611764#2611883 &lt;/shameless_plug&gt;
        • 一些 C 编译器支持二进制文字的 0b100101,但不幸的是,它是一个非标准扩展。
        • 请注意,虽然它没有在标准中定义,但一些编译器(特别是用于微控制器和嵌入式系统的编译器)为方便起见以0b00101010 的形式添加二进制语法。 SDCC 就是其中之一,我相信还有其他人也这样做。 (编辑:哈,打败我,@Joey!)
        【解决方案12】:

        基于其他一些答案,但这个答案将拒绝具有非法二进制文字的程序。前导零是可选的。

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

        【讨论】:

          【解决方案13】:

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

          int i;
          
          __asm {
              mov eax, 00000000000000000000000000000000b
              mov i,   eax
          }
          
          std::cout << i;
          

          好吧,这可能有点矫枉过正,但它确实有效。

          【讨论】:

          • 您的解决方案不是多平台的。在许多体系结构中,您不能在 C 中包含汇编代码。特别是在 Microsoft Visual Studio 编译器中,您可以(针对 x86 32 位编译时)。但是你怎么知道你的处理器是否有'eax'寄存器?想想手机中的 ARM 处理器、x64 处理器等。它们没有“eax”。 MIPS 处理器甚至没有命令“mov”
          【解决方案14】:

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

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

          【讨论】:

            【解决方案15】:

            你可以使用位集

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

            【讨论】:

              【解决方案16】:

              我通过确保以下人员的支持扩展了@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))
              

              这是雷纳托的使用示例:

              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; */
              

              【讨论】:

                【解决方案17】:

                只需使用 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];
                }
                

                在本例中,我将10 的二进制形式存储在x 中。

                8ul 定义了你的位大小,所以7ul 表示七位等等。

                【讨论】:

                  【解决方案18】:

                  从 C++14 开始,您可以使用二进制文字,现在它们是语言的一部分:

                  unsigned char a = 0b00110011;
                  

                  【讨论】:

                    【解决方案19】:

                    这是我没有添加 Boost 库的函数:

                    用法:BOOST_BINARY(00010001);

                    int BOOST_BINARY(int a){
                        int b = 0;
                        
                        for (int i = 0;i < 8;i++){
                            b += a % 10 << i;
                            a = a / 10;
                        }
                        
                        return b;
                    }
                    

                    【讨论】:

                    • 请不要通过破坏您的帖子为他人增加工作量。通过在 Stack Exchange (SE) 网络上发帖,您已在 CC BY-SA license 下授予 SE 分发内容的不可撤销的权利(无论您未来的选择如何)。根据 SE 政策,分发非破坏版本。因此,任何此类破坏性编辑都将被还原。请参阅How does deleting work?,详细了解如何在本网站上删除内容。
                    • 另外,我为您修复了代码格式,以防您删除了内容。
                    • 这个答案没有为问题提供任何新的见解,它的可用性仅限于最多 9 位二进制数。
                    【解决方案20】:

                    C++ 提供了一个名为std::bitset 的标准模板。喜欢就试试吧。

                    【讨论】:

                      【解决方案21】:

                      用法:二进制(00010001);

                      int BINARY(int a){ int b = 0;

                      for (int i = 0;i < 8;i++){
                          b += a % 10 << i;
                          a = a / 10;
                      }
                      
                      return b;
                      

                      }

                      【讨论】:

                      【解决方案22】:

                      您可以尝试使用bool 的数组:

                      bool i[8] = {0,0,1,1,0,1,0,1}
                      

                      【讨论】:

                      • 很多反对票,没有解释。这是您的解释:stackoverflow.com/questions/2064550/c-why-bool-is-8-bits-long 此外,数组中的每个元素都位于不同的内存地址。但我们希望在一个地址上有一系列压缩的 1 和 0。
                      • 关于此的另一件事是,它对案例的内存使用量非常大。我建议编写一个函数来更好地表示二进制数字以方便操作?
                      猜你喜欢
                      • 2018-10-04
                      • 2017-04-27
                      • 2010-11-20
                      • 1970-01-01
                      • 2011-03-05
                      • 1970-01-01
                      • 1970-01-01
                      相关资源
                      最近更新 更多