Tôi có thể sử dụng một chữ nhị phân trong C hoặc C ++ không?


190

Tôi cần phải làm việc với một số nhị phân.

Tôi đã thử viết:

const x = 00010000;

Nhưng nó không hoạt động.

Tôi biết rằng tôi có thể sử dụng số thập lục phân có cùng giá trị với 00010000, nhưng tôi muốn biết liệu có loại nào trong C ++ cho số nhị phân không và nếu không, có giải pháp nào khác cho vấn đề của tôi không?


51
Bạn biết đó 00010000là bát phân, phải không? (Và tuyên bố của bạn thiếu một loại.)
Keith Thompson

Ở đây cách hiện đại sử dụng chữ C ++.
Lol4t0

2
C ++ 14 đã thêm một tính năng cho việc này. Xem câu trả lời mới của tôi để biết thêm chi tiết ở phía dưới. Tất nhiên, nó đòi hỏi một trình biên dịch thực hiện nó.
lpapp

1
@FormlessCloud: Đây là các quy tắc cú pháp được đưa ra trong các tiêu chuẩn C và C ++ ( 0bchỉ xuất hiện trong C ++ 14). Chúng được thiết kế để rõ ràng.
Keith Thompson

2
Bản sao có thể có của chữ nhị phân?
MJ Rayburn

Câu trả lời:


70

Bạn có thể sử dụngBOOST_BINARY trong khi chờ C ++ 0x. :) BOOST_BINARYcó thể có một lợi thế so với triển khai mẫu trong chừng mực vì nó cũng có thể được sử dụng trong các chương trình C (nó được điều khiển bởi 100% tiền xử lý.)

Để thực hiện ngược lại (nghĩa là in ra một số ở dạng nhị phân), bạn có thể sử dụng itoachức năng không di động hoặc thực hiện theo cách riêng của mình .

Thật không may, bạn không thể thực hiện định dạng cơ sở 2 với các luồng STL (vì setbasesẽ chỉ tôn vinh các cơ sở 8, 10 và 16), nhưng bạn có thể sử dụng một std::stringphiên bản itoahoặc (ngắn gọn hơn, nhưng kém hiệu quả hơn một chút) 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;
}

sản xuất:

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

Cũng đọc The String Formatters of Manor Farm của Herb Sutter để có một cuộc thảo luận thú vị.


2
Như chính trang mà bạn liên kết nói, bạn chỉ có thể sử dụng 8, 10 hoặc 16 với setbase. Tuy nhiên:int main() { cout << bitset<8>(42); }

@Roger cảm ơn vì tiền bitsetboa, tôi đã sửa một chút về setbasetrước khi tôi thấy bình luận của bạn.
vladr

Dưới đây là hướng dẫn về nghĩa đen do người dùng định nghĩa trong c ++ 11: akrzemi1.wordpress.com/2012/10/23/user-dposed-literals-part-ii . Rõ ràng c ++ 1y (còn gọi là c ++ 14) sẽ bao gồm các chữ nhị phân trong tiêu chuẩn.
cheshirekow

274

Nếu bạn đang sử dụng GCC thì bạn có thể sử dụng tiện ích mở rộng GCC (được bao gồm trong tiêu chuẩn C ++ 14 ) cho việc này:

int x = 0b00010000;

2
Một số trình biên dịch khác có cách này hoặc các cách tương tự khác để thể hiện số trong cơ sở 2.
nargetoose

4
Sẽ rất tốt nếu có tiêu chuẩn này, nhưng tiếng kêu hỗ trợ ký hiệu tương tự.
Polemon

14
Nó hoạt động trong Clang, GCC và TCC. Nó không hoạt động trong PCC. Tôi không có trình biên dịch nào khác để kiểm tra.
Michas

6
Tôi đã thấy một số trình biên dịch hệ thống nhúng hỗ trợ nó. Tôi không biết bất kỳ lý do cụ thể nào không nên là một tính năng ngôn ngữ tiêu chuẩn.
năm11

5
@polemon open-std.org/jtc1/sc22/wg21/docs/ con / 2012 / n3472.pdf (C ++ 14.)
Jonathan Baldwin

98

Bạn có thể sử dụng chữ nhị phân. Chúng được chuẩn hóa trong C ++ 14. Ví dụ,

int x = 0b11000;

Hỗ trợ trong GCC

Hỗ trợ trong GCC bắt đầu trong GCC 4.3 (xem https://gcc.gnu.org/gcc-4.3/changes.html ) dưới dạng tiện ích mở rộng cho họ ngôn ngữ C (xem https://gcc.gnu.org/onlinesocs/gcc/ C-Tiện ích mở rộng.html # C-Tiện ích mở rộng ), nhưng vì GCC 4.9, giờ đây nó được công nhận là tính năng C ++ 14 hoặc tiện ích mở rộng (xem Sự khác biệt giữa chữ nhị phân GCC và chữ C ++ 14? )

Hỗ trợ trong Visual Studio

Hỗ trợ trong Visual Studio bắt đầu trong Visual Studio 2015 Preview (xem https://www.visualstudio.com/news/vs2015-preview-vs#C++ ).


5
Bạn có thể sử dụng 'để tách từng phần: "0b0000'0100'0100'0001
camino

1
@camino Rất vui vì bạn có thể mất người đầu tiên "
Nikos

Đây phải là câu trả lời được chấp nhận. Hầu hết các câu trả lời khác đều lỗi thời.
Alex

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

Chữ số ngoài cùng bên trái của chữ vẫn phải là 1, nhưng dù sao.


4
Phiên bản tốt hơn: bitbucket.org/kniht/scraps/src/tip/cpp/binary.hpp ( binary<10>::value == binary<010>::valuevà một số kiểm tra lỗi)

Bằng cách nào đó đã bỏ lỡ điều này trước khi tôi đăng câu trả lời gần như giống hệt của mình. Nhưng trong tôi, chữ số hàng đầu phải là 0, không phải 1.
Mark Ransom

4
Một phiên bản tốt hơn của ý tưởng mẫu này: code.google.com/p/cpp-binary-constants
Valentin Galea

@ValentinGalea - tại sao phiên bản google tốt hơn thế này?
AJed

Đây là ấn tượng kỳ lạ. Quá tệ, nó không hoạt động với số lượng bit cao.
Nhà vật lý lượng tử

31

Một vài trình biên dịch (thường là các trình biên dịch cho vi điều khiển ) có một tính năng đặc biệt được triển khai trong việc nhận ra các số nhị phân theo nghĩa đen bằng tiền tố "0b ..." trước số, mặc dù hầu hết các trình biên dịch (tiêu chuẩn C / C ++) không có tính năng đó và nếu nó là trường hợp, đây là giải pháp thay thế của tôi:

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

Nhược điểm (không phải là lớn như vậy):

  • Các số nhị phân phải được nhóm 4 cho 4;
  • Các chữ nhị phân phải chỉ là số nguyên không dấu;

Ưu điểm :

  • Tổng số tiền xử lý được điều khiển, không phải spending processor timetrong các hoạt động vô nghĩa ( like "?.. :..", "<<", "+") cho chương trình thực thi (nó có thể được thực hiện hàng trăm lần trong ứng dụng cuối cùng);
  • Nó hoạt động "mainly in C"trình biên dịch và C ++ là tốt ( template+enum solution works only in C++ compilers);
  • Nó chỉ có giới hạn về "độ dài" để thể hiện các giá trị "hằng số theo nghĩa đen". Sẽ có giới hạn độ dài sớm (thường là 8 bit: 0-5555) nếu người ta đã biểu thị các giá trị không đổi bằng cách phân tích giải quyết các "enum solution" (usually 255 = reach enum definition limit)giới hạn "hằng số theo nghĩa đen", trong trình biên dịch cho phép số lượng lớn hơn;
  • Một số giải pháp khác yêu cầu số lượng định nghĩa không đổi quá mức (theo tôi là quá nhiều định nghĩa) bao gồm dài hoặc several header files(trong hầu hết các trường hợp không dễ đọc và dễ hiểu, và làm cho dự án trở nên bối rối và mở rộng không cần thiết, như sử dụng "BOOST_BINARY()");
  • Tính đơn giản của giải pháp: dễ đọc, dễ hiểu và có thể điều chỉnh cho các trường hợp khác (có thể được mở rộng để nhóm 8 đến 8);

Tại sao ví dụ B_0100không được sử dụng (thay vì 0100)? Như trong ví dụ char b = BYTE(0100,0001);.
Peter Mortensen

@PeterMortensen B_ được thêm bởi _B2Hchức năng tiền xử lý.
mxmlnkn

20

Chủ đề này có thể giúp đỡ.

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

Nó hoạt động! (Tất cả các khoản tín dụng cho Tom Torfs.)


tôi không thực sự hiểu (tôi mới bắt đầu lập trình & đặc biệt là về C ++) nhưng có vẻ thú vị vì vậy tôi sẽ cố gắng hiểu nó sau một số nghiên cứu về C ++, cảm ơn
hamza

3
Macro B8 hoạt động bằng cách chuyển đổi chữ "nhị phân" thành chữ lục giác và trích xuất mỗi bit thứ 4.
dan04

Tôi tự hỏi 0x ## n ## LU nghĩa là gì? Chưa bao giờ gặp phải cú pháp như vậy.
Federico A. Ramponi

@hamza: nó thực sự khá phức tạp. Nhưng những gì bạn cần hiểu chỉ là từ #include <stdio> trở đi.
Federico A. Ramponi

8
@Federico: ##Toán tử tiền xử lý dán các mã thông báo với nhau. Vì vậy, trong trường hợp này, nếu bạn gọi HEX__(10), nó sẽ mở rộng ra 0x10LU.
James McNellis

18

Như đã trả lời, các tiêu chuẩn C không có cách nào để viết trực tiếp các số nhị phân. Tuy nhiên, có các phần mở rộng trình biên dịch và rõ ràng C ++ 14 bao gồm 0btiền tố cho nhị phân. (Lưu ý rằng câu trả lời này ban đầu được đăng vào năm 2010)

Một cách giải quyết phổ biến là bao gồm một tệp tiêu đề với các macro trợ giúp . Một tùy chọn dễ dàng cũng là tạo một tệp bao gồm các định nghĩa macro cho tất cả các mẫu 8 bit, ví dụ:

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

Điều này chỉ dẫn đến 256 #definegiây và nếu cần các hằng số nhị phân 8 bit lớn hơn, các định nghĩa này có thể được kết hợp với các ca và OR, có thể với các macro trợ giúp (ví dụ BIN16(B00000001,B00001010):). (Có các macro riêng lẻ cho mỗi 16 bit, chưa kể 32 bit, giá trị là không hợp lý.)

Tất nhiên nhược điểm là cú pháp này yêu cầu viết tất cả các số 0 đứng đầu, nhưng điều này cũng có thể làm cho nó rõ ràng hơn cho việc sử dụng như cài đặt cờ bit và nội dung của các thanh ghi phần cứng. Đối với một macro giống như hàm dẫn đến một cú pháp không có thuộc tính này, hãy xem bithacks.hliên kết ở trên.


2
Vì vậy, CPP cần đọc một tệp lớn đến mức nào nếu bạn có tất cả các macro cho một long long int?
wilmustell

3
@wilmustell: Và sự liên quan của điều đó là gì khi tôi chỉ định tất cả các mẫu 8 bit bit (= 256 dòng) và đề xuất kết hợp số lượng lớn hơn từ những mẫu đó? Ngay cả BOOST_BINARY của câu trả lời được chấp nhận cũng xác định tất cả các mẫu 8 bit trong tiêu đề '
Arkku

16

Tư duy kỹ thuật quá mức C ++ đã được tính toán tốt trong các câu trả lời khác ở đây. Đây là nỗ lực của tôi trong việc thực hiện nó với một tư duy C, keep-it-Simple-ffs:

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

12

C không có nguồn gốc ký hiệu cho số nhị phân thuần túy. Đặt cược tốt nhất của bạn ở đây sẽ là bát phân (ví dụ 07777) thập lục phân (ví dụ 0xfff).


11

Bạn có thể sử dụng hàm tìm thấy trong câu hỏi này để nhận tới 22 bit trong C ++. Đây là mã từ liên kết, được chỉnh sửa phù hợp:

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

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

Vì vậy, bạn có thể làm một cái gì đó như binary<0101011011>::value.


7

Đơn vị nhỏ nhất bạn có thể làm việc là một byte (thuộc charloại). Bạn có thể làm việc với các bit mặc dù bằng cách sử dụng các toán tử bitwise.

Đối với chữ nguyên, bạn chỉ có thể làm việc với các số thập phân (cơ số 10), bát phân (cơ sở 8) hoặc số thập lục phân (cơ sở 16). Không có chữ nhị phân (cơ sở 2) trong C và C ++.

Số bát phân có tiền tố 0và số thập lục phân được tiền tố với 0x. Số thập phân không có tiền tố.

Trong C ++ 0x, bạn sẽ có thể thực hiện những gì bạn muốn bằng cách thông qua các chữ được xác định bởi người dùng .


ít nhất tôi có thể hiển thị giá trị nhị phân của một hệ thập lục phân trong một bản in hoặc một hàm cout không?
hamza

Có, bạn có thể <shameless_plug> stackoverflow.com/questions/2611764#2611883 </shameless_plug>
vladr

5
Một số trình biên dịch C hỗ trợ 0b100101 cho chữ nhị phân, nhưng thật không may, đây là một phần mở rộng không chuẩn.
Joey Adams

3
Lưu ý rằng, mặc dù không được xác định trong tiêu chuẩn, một số trình biên dịch (đáng chú ý là các trình biên dịch cho các bộ vi điều khiển và các hệ thống nhúng) thêm cú pháp cho nhị phân ở dạng 0b00101010để thuận tiện. SDCC là một, và tôi chắc chắn cũng có những người khác cũng vậy. (Chỉnh sửa: Hah, đánh bại tôi với nó, @Joey!)
Matt B.

5

Bạn cũng có thể sử dụng lắp ráp nội tuyến như thế này:

int i;

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

std::cout << i;

Được rồi, nó có thể hơi quá mức, nhưng nó hoạt động.


3
Giải pháp của bạn không phải là đa nền tảng. Trong nhiều kiến ​​trúc, bạn không thể bao gồm mã lắp ráp trong C. Cụ thể trong trình biên dịch Microsoft Visual studio bạn có thể (khi được biên dịch cho x86 32 bit). Nhưng làm thế nào để bạn biết nếu bộ xử lý của bạn có đăng ký 'eax'? Hãy nghĩ về bộ xử lý ARM trong điện thoại di động, bộ xử lý x64, v.v. Họ không có 'eax'. Bộ xử lý MIPS thậm chí không có lệnh 'Mov'
DanielHsH

4

Dựa trên một số câu trả lời khác, nhưng câu trả lời này sẽ từ chối các chương trình có nghĩa đen nhị phân bất hợp pháp. Số không hàng đầu là tùy chọn.

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

Thí dụ:

#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

"Loại" của một số nhị phân giống như bất kỳ số thập phân, thập lục phân hoặc bát phân nào: int(hoặc thậm chí char, ngắn, dài dài).

Khi bạn gán một hằng số, bạn không thể gán nó với 11011011 (tò mò và không may), nhưng bạn có thể sử dụng hex. Hex là một chút dễ dàng để dịch về mặt tinh thần. Chunk trong nibble (4 bit) và dịch sang một ký tự trong [0-9a-f].


2

Bạn có thể sử dụng một bitet

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

2

Tôi đã mở rộng câu trả lời hay được đưa ra bởi @ renato-đèn chùm bằng cách đảm bảo sự hỗ trợ của:

  • _NIBBLE_(…) - 4 bit, 1 nibble làm đối số
  • _BYTE_(…) - 8 bit, 2 nibble làm đối số
  • _SLAB_(…) - 12 bit, 3 nibble làm đối số
  • _WORD_(…) - 16 bit, 4 nibble làm đối số
  • _QUINTIBBLE_(…) - 20 bit, 5 nibble làm đối số
  • _DSLAB_(…) - 24 bit, 6 nibble làm đối số
  • _SEPTIBBLE_(…) - 28 bit, 7 nibble làm đối số
  • _DWORD_(…) - 32 bit, 8 nibble làm đối số

Tôi thực sự không chắc lắm về các điều khoản của Quintibble và và septibble. Nếu bất cứ ai biết bất kỳ thay thế xin vui lòng cho tôi biết.

Đây là macro viết lại:

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

Và đây là ví dụ sử dụng của 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

Chỉ cần sử dụng thư viện chuẩn trong C ++:

#include <bitset>

Bạn cần một biến loại std::bitset:

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

Trong ví dụ này, tôi được lưu trữ dưới dạng nhị phân của 10trong x.

8ulđịnh nghĩa kích thước của các bit của bạn, 7ulcó nghĩa là bảy bit và cứ thế.



Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.