C 또는 C ++에서 이진 리터럴을 사용할 수 있습니까?


191

이진수로 작업해야합니다.

나는 쓰기를 시도했다 :

const x = 00010000;

그러나 작동하지 않았습니다.

와 같은 값을 가진 16 진수를 사용할 수 있다는 00010000것을 알고 있지만 이진 숫자에 대한 C ++에 유형이 있는지, 그렇지 않은 경우 내 문제에 대한 다른 해결책이 있습니까?


51
당신은 그것이 000100008 진수 라는 것을 알고 있습니까? (그리고 당신의 선언에는 유형이 없습니다.)
Keith Thompson

다음은 C ++ 리터럴을 사용하여 현대적인 방법.
Lol4t0

2
C ++ 14는 이에 대한 기능을 추가했습니다. 자세한 내용은 하단의 새 답변을 참조하십시오. 물론이를 구현하는 컴파일러가 필요합니다.
lpapp December

1
@FormlessCloud : C 및 C ++ 표준에 지정된 구문 규칙입니다 ( 0bC ++ 14에만 나타남). 그들은 모호하지 않게 설계되었습니다.
Keith Thompson

답변:


70

C ++ 0x를 기다리는 동안 사용할BOOST_BINARY 수 있습니다 . :) BOOST_BINARY논란의 여지없이 C 프로그램에서도 사용할 수있는 한 템플릿 구현에 비해 이점이 있습니다 (100 % 전 처리기 구동).

대화를하기 위해 (즉, 이진 형식으로 숫자를 인쇄하기 위해) 이식 불가능한 itoa함수 를 사용하거나 직접 구현할 수 있습니다 .

불행히도 STL 스트림을 사용하여 기본 2 형식을 수행 할 수는 없지만 ( setbase기준 8, 10 및 16 만 존중 하므로 ) 버전을 사용 하거나 (보다 간결하지만 약간 덜 효율적 임) 버전을 사용할 있습니다 .std::stringitoastd::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의 Manor FarmThe String Formatters를 읽으십시오 .


2
링크하는 바로 페이지에 표시된 것처럼 setbase에는 8, 10 또는 16 만 사용할 수 있습니다. 그러나 :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

275

GCC를 사용 하는 경우이를 위해 GCC 확장 ( C ++ 14 표준에 포함 )을 사용할 수 있습니다 .

int x = 0b00010000;

2
여러 다른 컴파일러는 기본 2의 숫자를 표현하는이 또는 기타 유사한 방법이
nategoose

4
이것을 표준화하면 좋겠지 만 clang도 같은 표기법을 지원합니다.
polemon

14
Clang, GCC 및 TCC에서 작동합니다. PCC에서는 작동하지 않습니다. 테스트 할 다른 컴파일러가 없습니다.
Michas

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 Preview에서 시작된 Visual Studio 지원 ( https://www.visualstudio.com/news/vs2015-preview-vs#C++ 참조) ) .


5
'를 사용하여 각 부분을 분리 할 수 ​​있습니다. "0b0000'0100'0100'0001
camino

1
@ 카미노 좋은 첫 번째를 풀 수 있습니다 "
Nikos

이것이 정답입니다. 다른 답변의 대부분은 구식입니다.
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';

리터럴의 가장 왼쪽 숫자는 여전히 1이어야하지만 그럼에도 불구하고.


4
더 나은 버전 : bitbucket.org/kniht/scraps/src/tip/cpp/binary.hpp ( binary<10>::value == binary<010>::value및 일부 오류 확인)

내가 거의 같은 답변을 게시하기 전에 어떻게 든이 것을 놓쳤다. 그러나 내 앞자리는 1이 아닌 0이어야합니다.
Mark Ransom

4
이 템플릿 아이디어의 더 나은 버전 : code.google.com/p/cpp-binary-constants
발렌틴 GALEA에게

@ValentinGalea-왜 Google 버전이 이것보다 낫습니까?
AJed

이것은 인상적입니다. 비트 수가 많으면 작동하지 않습니다.
양자 물리학 자

31

일부 컴파일러 (보통 마이크로 컨트롤러 용 컴파일러 )에는 대부분의 컴파일러 (C / C ++ 표준)에 이러한 기능이 없지만 대부분의 컴파일러 (C / C ++ 표준)에는 해당되지 않지만, 숫자 앞에 접두사 "0b ..."로 리터럴 이진 숫자를 인식하도록 구현 된 특수 기능 이 있습니다. 이 경우 내 대안 솔루션입니다.

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

단점 (그다지 큰 것은 아닙니다) :

  • 이진수는 4x4로 그룹화해야합니다.
  • 이진 리터럴은 부호없는 정수 여야합니다.

장점 :

  • spending processor time무의미한 작업이 아닌 전체 전 처리기 구동 (like "?.. :..", "<<", "+"실행 가능한 프로그램에 대한 )이 (최종 응용 프로그램에서 수백 번 수행 될 수 있음);
  • "mainly in C"컴파일러와 C ++도 작동 합니다 ( template+enum solution works only in C++ compilers);
  • "문자 상수"값을 표현하기 위해 "길이"의 한계 만 있습니다. "enum solution" (usually 255 = reach enum definition limit)컴파일러에서 "리터럴 상수"한계를 다르게 해석하여 상수 값을 표현한 경우 컴파일러에서 더 큰 숫자를 허용하면 초기 경도 제한 (보통 8 비트 : 0-255)이 발생했을 것 입니다.
  • 일부 다른 솔루션은 길거나 several header files(대부분의 경우 쉽게 읽고 이해할 수 없으며 프로젝트를 사용하는 것과 같이 불필요하게 혼란스럽고 확장되게합니다 )을 포함하여 많은 수의 상수 정의 (제 의견으로는 너무 많은 정의 "BOOST_BINARY()")를 요구합니다.
  • 솔루션의 단순성 : 다른 경우에 대해 쉽게 읽고 이해하고 조절할 수 있습니다 (8x8 그룹화도 확장 가능).

예를 들어 B_0100(대신 0100) 사용하지 않는 이유는 무엇 입니까? 예를 들어 char b = BYTE(0100,0001);.
피터 Mortensen

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

효과가있다! (모든 크레딧은 Tom Torfs에게 전달됩니다.)


나는 정말로 이해하지 못했습니다 (프로그래밍 및 특히 C ++의 초보자). 흥미로워 서 좀 더 C ++ 연구 후에 이해하려고 노력할 것입니다.
hamza

3
B8 매크로는 "이진"리터럴을 16 진 리터럴로 변환하고 매 4 번째 비트를 추출하여 작동합니다.
dan04

0x ## n ## LU의 의미가 궁금합니다. 그런 구문은 없었습니다.
Federico A. Ramponi

@ hamza : 그것은 실제로 다소 복잡합니다. 그러나 이해해야 할 것은 #include <stdio>부터입니다.
Federico A. Ramponi 1

8
@Federico : ##전 처리기 연산자는 토큰을 함께 붙여 넣 습니다. 따라서이 HEX__(10)경우을 호출 하면로 확장됩니다 0x10LU.
James McNellis

18

이미 대답했듯이 C 표준은 이진수를 직접 쓰는 방법이 없습니다. 그러나 컴파일러 확장이 있지만 분명히 C ++ 14에는0b 바이너리 접두사가 . (이 답변은 원래 2010 년에 게시되었습니다.)

널리 사용되는 해결 방법은 도우미 매크로 가 포함 된 헤더 파일 을 포함 시키는 것 입니다. 하나의 쉬운 옵션은 또한 모든 8 비트 패턴에 대한 매크로 정의를 포함하는 파일을 생성하는 것입니다.

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

이로 인해 256 초만 발생하고 #define8 비트 이진 상수보다 큰 경우 이러한 정의를 시프트 및 OR과 함께 가능하면 도우미 매크로와 함께 사용할 수 있습니다 (예 :BIN16(B00000001,B00001010) . (32 비트는 물론 16 비트마다 개별 매크로를 갖는 것은 가치가 없습니다.)

물론 단점은이 구문은 모든 선행 0을 작성해야하지만, 이는 비트 플래그 및 하드웨어 레지스터의 내용 설정과 같은 용도로 더 명확해질 수 있다는 것입니다. 이 속성이없는 구문을 생성하는 함수와 유사한 매크로에 대해서는 bithacks.h위의 링크를 참조하십시오 .


2
따라서 long long int?에 대한 모든 매크로가 있다면 CPP가 얼마나 큰 파일을 읽어야 합니까?
wilhelmtell

3
@ wilhelmtell : 그리고 "모든 8 비트 패턴"(= 256 줄)을 지정하고 그 중에서 더 많은 양을 결합 할 것을 제안 했을 때의 관련성은 무엇 입니까? 허용 된 답변의 BOOST_BINARY조차도 헤더에 모든 8 비트 패턴을 정의합니다.
Arkku

16

C ++ 오버 엔지니어링 마인드는 이미 다른 답변에서 잘 설명되어 있습니다. 다음은 C, 간단하고 간단한 ffs 사고 방식으로 수행하려는 시도입니다.

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

12

C에는 순수 이진수에 대한 고유 표기법 이 없습니다 . 여기서 가장 좋은 방법 은 16 진수 (예 :)의 8 진수 (예 :) 입니다.077770xfff


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 진수 (10 진), 8 진 (8 진) 또는 16 진 (16 진) 숫자 만 사용할 수 있습니다. C 또는 C ++에는 이진 (기본 2) 리터럴이 없습니다.

8 0진수는 접두사가 붙고 16 진수는 접두사가 붙습니다 0x. 십진수에는 접두사가 없습니다.

C ++ 0x에서는 사용자 정의 리터럴을 통해 원하는 것을 수행 할 수 있습니다 .


인쇄 또는 cout 함수에서 적어도 16 진의 이진 값을 표시 할 수 있습니까?
hamza

네 당신은 <shameless_plug> stackoverflow.com/questions/2611764#2611883 </shameless_plug>
vladr April

5
일부 C 컴파일러는 이진 리터럴에 대해 0b100101을 지원하지만 불행히도 비표준 확장입니다.
Joey Adams

3
표준에 정의되어 있지는 않지만 일부 컴파일러 (특히 마이크로 컨트롤러 및 임베디드 시스템 용 컴파일러) 0b00101010는 편의를 위해 이진 구문을 양식에 추가 합니다. SDCC는 하나이며 다른 것도 있습니다. (편집 : Hah, @Joey!)
Matt B.

5

다음과 같이 인라인 어셈블리를 사용할 수도 있습니다.

int i;

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

std::cout << i;

좋아, 다소 과잉 일 수도 있지만 작동합니다.


3
귀하의 솔루션은 다중 플랫폼이 아닙니다. 많은 아키텍처에서는 C로 어셈블리 코드를 포함 할 수 없습니다. 특히 Microsoft Visual Studio 컴파일러에서는 (x86 32 비트 용으로 컴파일 된 경우) 할 수 있습니다. 그러나 프로세서에 'eax'레지스터가 있는지 어떻게 알 수 있습니까? 휴대폰, x64 프로세서 등의 ARM 프로세서는 'eax'가 없습니다. MIPS 프로세서에는 'mov'명령도 없습니다
DanielHsH

4

다른 답변을 기반으로하지만이 방법은 잘못된 이진 리터럴이있는 프로그램을 거부합니다. 선행 0은 선택 사항입니다.

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

이진수의 "유형"은 10 진수, 16 진수 또는 8 진수와 동일합니다 int(또는 char, short, long long).

상수를 할당하면 11011011 (호기심과 불행하게도)로 할당 할 수 없지만 16 진수를 사용할 수 있습니다. 16 진수는 정신적으로 번역하기가 조금 더 쉽습니다. 니블 (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비트의 크기를 정의하므로 7ul7 비트 등을 의미합니다.



당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.