이진 형식으로 인쇄 할 printf 변환기가 있습니까?


434

16 진수 또는 8 진수로 printf를 사용하여 인쇄 할 수 있습니다. 이진 또는 임의의 기준으로 인쇄 할 형식 태그가 있습니까?

gcc를 실행 중입니다.

printf("%d %x %o\n", 10, 10, 10); //prints "10 A 12\n"
print("%b\n", 10); // prints "%b\n"

내가 아는 한 printf를 사용 하여이 작업을 수행 할 수 없습니다. 분명히이 작업을 수행하는 도우미 메서드를 작성할 수는 있지만 원하는 방향으로 들리지 않습니다.
Ian P

이를 위해 사전 정의 된 형식이 없습니다. 직접 문자열로 변환 한 다음 문자열을 인쇄해야합니다.
rslite

빠른 Google 검색으로이 페이지에서 유용한 정보를 얻을 수있었습니다. forums.macrumors.com/archive/index.php/t-165959.html
Ian P

12
ANSI 표준 C 라이브러리의 일부가 아닙니다. 이식 가능한 코드를 작성하는 경우 가장 안전한 방법은 직접 코드를 작성하는 것입니다.
tomlogic

C ++에서 이진 문자열로 변환하는 표준 및 일반 (모든 길이의 정수 유형에 대한) 솔루션 : stackoverflow.com/a/31660310/1814353
luart

답변:


266

해 키지 만 나를 위해 작동합니다.

#define BYTE_TO_BINARY_PATTERN "%c%c%c%c%c%c%c%c"
#define BYTE_TO_BINARY(byte)  \
  (byte & 0x80 ? '1' : '0'), \
  (byte & 0x40 ? '1' : '0'), \
  (byte & 0x20 ? '1' : '0'), \
  (byte & 0x10 ? '1' : '0'), \
  (byte & 0x08 ? '1' : '0'), \
  (byte & 0x04 ? '1' : '0'), \
  (byte & 0x02 ? '1' : '0'), \
  (byte & 0x01 ? '1' : '0') 
printf("Leading text "BYTE_TO_BINARY_PATTERN, BYTE_TO_BINARY(byte));

멀티 바이트 유형의 경우

printf("m: "BYTE_TO_BINARY_PATTERN" "BYTE_TO_BINARY_PATTERN"\n",
  BYTE_TO_BINARY(m>>8), BYTE_TO_BINARY(m));

불행히도 모든 여분의 따옴표가 필요합니다. 이 접근법은 매크로의 효율성 위험이 BYTE_TO_BINARY있지만 ( 함수를의 인수로 전달하지 마십시오 ) 여기 다른 제안에서 메모리 문제와 strcat의 여러 호출을 피하십시오.


13
그리고 또한에 invocable 여러 번 할 수있는 장점이 printf와 함께있는 사람 static버퍼 수 없습니다입니다.
Patrick Schlüter

4
나는을 변경할 수있는 자유를 촬영했습니다 %d에를 %c가 더 빨리해야하기 때문에, ( %d반면, digit-> 문자 변환을 수행하는 %c단순히 인수 출력

3
16, 32, 64 비트 int를 지원하는이 매크로의 확장 버전을 게시했습니다 : stackoverflow.com/a/25108449/432509
ideasman42

2
이 방법은 스택 친화적이지 않습니다. int시스템에서 32 비트 라고 가정하면 단일 32 비트 값을 인쇄하려면 32 * 4 바이트 값을위한 공간이 필요합니다. 총 128 바이트 스택 크기에 따라 문제가 될 수도 있고 아닐 수도 있습니다.
user694733

1
매크로에서 바이트 주위에 괄호를 추가하는 것이 중요하거나 작업을 보낼 때 문제가 발생할 수 있습니다. BYTE_TO_BINARY (a | b)-> a | b & 0x01! = (a | b) & 0x01
Ivan Hoffmann

203

모든 데이터 유형에 대한 이진 인쇄

//assumes little endian
void printBits(size_t const size, void const * const ptr)
{
    unsigned char *b = (unsigned char*) ptr;
    unsigned char byte;
    int i, j;

    for (i=size-1;i>=0;i--)
    {
        for (j=7;j>=0;j--)
        {
            byte = (b[i] >> j) & 1;
            printf("%u", byte);
        }
    }
    puts("");
}

테스트

int main(int argv, char* argc[])
{
        int i = 23;
        uint ui = UINT_MAX;
        float f = 23.45f;
        printBits(sizeof(i), &i);
        printBits(sizeof(ui), &ui);
        printBits(sizeof(f), &f);
        return 0;
}

8
제안 size_t i; for (i=size; i-- > 0; )피하기 위해 size_t대의 int잘못 일치.
chux-복원 모니카

1
누군가이 코드의 논리에 대해 자세히 설명해 주시겠습니까?
jII

2
각 바이트를 가져옵니다 ptr(외부 루프). 그런 다음 각 비트에 대해 현재 바이트 (내부 루프)에 대해 현재 비트 ( 1 << j)로 바이트를 마스크하십시오 . 오른쪽으로 이동하면 0 ( 0000 0000b) 또는 1 ( 0000 0001b)을 포함하는 바이트가 됩니다. format을 사용하여 결과 바이트 printf를 인쇄하십시오 %u. HTH.
nielsbot

1
@ ZX9 루프 종료 시점을 결정하기 위해 주석 과 함께 사용 된 제안 된 코드 에 유의하십시오. >size_t>=
chux-Reinstate Monica

3
@ 여전히 ZX9 코더의 가장자리 케이스 사용을 고려 조심해야 않는 한 당신의 유용한 원래 주석 >>=서명되지 않은 유형입니다. 0부호없는 엣지 케이스이며 덜 일반적으로 부호있는 수학과 달리 일반적으로 발생합니다 INT_MAX/INT_MIN.
chux-복원 Monica Monica

151

다음은 원하는 것을 수행하는 기술을 보여주는 빠른 해킹입니다.

#include <stdio.h>      /* printf */
#include <string.h>     /* strcat */
#include <stdlib.h>     /* strtol */

const char *byte_to_binary
(
    int x
)
{
    static char b[9];
    b[0] = '\0';

    int z;
    for (z = 128; z > 0; z >>= 1)
    {
        strcat(b, ((x & z) == z) ? "1" : "0");
    }

    return b;
}

int main
(
    void
)
{
    {
        /* binary string to int */

        char *tmp;
        char *b = "0101";

        printf("%d\n", strtol(b, &tmp, 2));
    }

    {
        /* byte to binary string */

        printf("%s\n", byte_to_binary(5));
    }

    return 0;
}

2
이것은 printf에 대한 이스케이프 오버로드를 작성하는 사용자 정의보다 확실히 "이상한"것입니다. 코드를 처음 접하는 개발자도 이해하기 쉽습니다.
퓨리어스 코더

43
몇 가지 변경 사항 strcat은 루프의 각 패스에서 단일 문자를 문자열에 추가하는 비효율적 인 방법입니다. 대신 a를 추가 char *p = b;하고 내부 루프를로 바꿉니다 *p++ = (x & z) ? '1' : '0'. z256 (2 ^ 8) 대신 128 (2 ^ 7)부터 시작해야합니다. (쓰레드 안전을 위해) 사용할 버퍼에 포인터를 가져와 업데이트를 고려하십시오 inet_ntoa().
tomlogic

3
@EvilTeach : 삼항 연산자를 매개 변수로 사용하고 있습니다 strcat()! strcat과제에 대한 역 참조 된 포인터를 사후 증가시키는 것보다 이해하기 쉽다는 데 동의 하지만 초보자도 표준 라이브러리를 올바르게 사용하는 방법을 알아야합니다. 할당을 위해 인덱스 배열을 사용하는 것이 좋은 데모 일 것입니다 (실제로 b함수를 호출 할 때마다 모두 0으로 재설정되지 않기 때문에 실제로 작동 합니다).
tomlogic

3
무작위 : 이진 버퍼 문자는 정적이며 할당에서 모든 0으로 지워집니다. 이것은 처음 실행될 때만 지워지고 그 후에 지워지지 않고 대신 마지막 값을 사용합니다.
markwatson

8
또한 함수를 다시 호출 한 후 이전 결과가 유효하지 않다는 것을 문서화해야하므로 호출자는 다음과 같이 사용하지 않아야합니다 printf("%s + %s = %s", byte_to_binary(3), byte_to_binary(4), byte_to_binary(3+4)).
Paŭlo Ebermann

84

glibc에는 바이너리 변환 지정자가 없습니다.

glibc의 printf () 함수 계열에 사용자 정의 변환 유형을 추가 할 수 있습니다. register_printf_function 참조 을 참조하십시오. 응용 프로그램 코드를 단순화하여 사용할 수 있도록 사용자 지정 % b 변환을 직접 사용할 수 있습니다.

다음은 glibc에서 사용자 정의 printf 형식을 구현하는 방법 의 입니다.


나는 항상 다른 기수를 원했던 제한된 경우에 대해 내 자신의 v [snf] printf ()를 작성했습니다.
Jamie

3
warning: 'register_printf_function' is deprecated [-Wdeprecated-declarations]그래도 동일한 기능을 수행하는 새로운 기능이 있습니다 register_printf_specifier(). 새로운 사용의 예는 여기에서 찾을 수 있습니다 : codereview.stackexchange.com/q/219994/200418을
Cacahuete 프리 토를

47

작은 테이블을 사용하여 속도를 향상시킬 수 있습니다 1 . 예를 들어 바이트를 반전시키는 것과 같은 내장 기술에서 비슷한 기술이 유용합니다.

const char *bit_rep[16] = {
    [ 0] = "0000", [ 1] = "0001", [ 2] = "0010", [ 3] = "0011",
    [ 4] = "0100", [ 5] = "0101", [ 6] = "0110", [ 7] = "0111",
    [ 8] = "1000", [ 9] = "1001", [10] = "1010", [11] = "1011",
    [12] = "1100", [13] = "1101", [14] = "1110", [15] = "1111",
};

void print_byte(uint8_t byte)
{
    printf("%s%s", bit_rep[byte >> 4], bit_rep[byte & 0x0F]);
}

1 주로 옵티마이 저가 그리 공격적이지 않고 속도 차이가 보이는 임베디드 응용 프로그램을 말합니다.


27

최하위 비트를 인쇄하여 오른쪽으로 옮기십시오. 정수가 0이 될 때까지이 작업을 수행하면 선행 0없이 이진 표현이 인쇄되지만 역순으로 인쇄됩니다. 재귀를 사용하면 순서를 쉽게 수정할 수 있습니다.

#include <stdio.h>

void print_binary(int number)
{
    if (number) {
        print_binary(number >> 1);
        putc((number & 1) ? '1' : '0', stdout);
    }
}

나에게 이것은 문제에 대한 가장 깨끗한 해결책 중 하나입니다. 0b접두사와 후행 줄 바꿈 문자 를 좋아한다면 함수를 래핑하는 것이 좋습니다.

온라인 데모


오류 : 함수 호출에 필요한 인수가 너무 적습니다. 예상 2는 1 putc ((number & 1)? '1': '0');
Koray Tugay

@KorayTugay 지적 해 주셔서 감사합니다. 함수 호출을 수정하고 데모를 추가했습니다.
danijar

6
주어진 숫자가 음수이면 함수는 끝없는 재귀 호출에 들어가기 때문에 부호없는 int 숫자도 사용해야합니다.
Puffy

ASCII에서 '0'+ 1 = '1'이후보다 효율적인 접근 방식 :putc('0'+(number&1), stdout);
Roger Dueck

22

@William 와이트의 답변에 따라,이 제공하는 매크로이다 int8, 16, 3264재사용 버전 INT8피하기 반복에 매크로를.

/* --- PRINTF_BYTE_TO_BINARY macro's --- */
#define PRINTF_BINARY_PATTERN_INT8 "%c%c%c%c%c%c%c%c"
#define PRINTF_BYTE_TO_BINARY_INT8(i)    \
    (((i) & 0x80ll) ? '1' : '0'), \
    (((i) & 0x40ll) ? '1' : '0'), \
    (((i) & 0x20ll) ? '1' : '0'), \
    (((i) & 0x10ll) ? '1' : '0'), \
    (((i) & 0x08ll) ? '1' : '0'), \
    (((i) & 0x04ll) ? '1' : '0'), \
    (((i) & 0x02ll) ? '1' : '0'), \
    (((i) & 0x01ll) ? '1' : '0')

#define PRINTF_BINARY_PATTERN_INT16 \
    PRINTF_BINARY_PATTERN_INT8              PRINTF_BINARY_PATTERN_INT8
#define PRINTF_BYTE_TO_BINARY_INT16(i) \
    PRINTF_BYTE_TO_BINARY_INT8((i) >> 8),   PRINTF_BYTE_TO_BINARY_INT8(i)
#define PRINTF_BINARY_PATTERN_INT32 \
    PRINTF_BINARY_PATTERN_INT16             PRINTF_BINARY_PATTERN_INT16
#define PRINTF_BYTE_TO_BINARY_INT32(i) \
    PRINTF_BYTE_TO_BINARY_INT16((i) >> 16), PRINTF_BYTE_TO_BINARY_INT16(i)
#define PRINTF_BINARY_PATTERN_INT64    \
    PRINTF_BINARY_PATTERN_INT32             PRINTF_BINARY_PATTERN_INT32
#define PRINTF_BYTE_TO_BINARY_INT64(i) \
    PRINTF_BYTE_TO_BINARY_INT32((i) >> 32), PRINTF_BYTE_TO_BINARY_INT32(i)
/* --- end macros --- */

#include <stdio.h>
int main() {
    long long int flag = 1648646756487983144ll;
    printf("My Flag "
           PRINTF_BINARY_PATTERN_INT64 "\n",
           PRINTF_BYTE_TO_BINARY_INT64(flag));
    return 0;
}

이 결과는 다음과 같습니다.

My Flag 0001011011100001001010110111110101111000100100001111000000101000

가독성을 위해 다음과 같은 구분 기호를 추가 할 수 있습니다.

My Flag 00010110,11100001,00101011,01111101,01111000,10010000,11110000,00101000

이것은 우수하다. 최하위 비트로 시작하는 비트를 인쇄해야하는 특별한 이유가 있습니까?
gaganso 2016 년

2
쉼표를 어떻게 추가 하시겠습니까?
nmz787

PRINTF_BYTE_TO_BINARY_INT#선택적으로 사용할 그룹화 된 버전의 정의를 추가합니다 .
ideasman42

16

다음은 재진입 문제 나 인수의 크기 / 유형에 대한 제한이없는 함수 버전입니다.

#define FMT_BUF_SIZE (CHAR_BIT*sizeof(uintmax_t)+1)
char *binary_fmt(uintmax_t x, char buf[static FMT_BUF_SIZE])
{
    char *s = buf + FMT_BUF_SIZE;
    *--s = 0;
    if (!x) *--s = '0';
    for(; x; x/=2) *--s = '0' + x%2;
    return s;
}

이 코드는 2를 원하는베이스로 바꾸면 2에서 10 사이의베이스에 대해서도 잘 작동합니다. 사용법은 :

char tmp[FMT_BUF_SIZE];
printf("%s\n", binary_fmt(x, tmp));

x완전한 표현은 어디에 있습니까 ?


7
예, 그렇게 할 수 있습니다 . 그러나 정말 나쁜 디자인입니다. 스레드 또는 재진입이없는 경우에도 호출자는 정적 버퍼가 재사용되고 있으며 이와 같은 기능 char *a = binary_fmt(x), *b = binary_fmt(y);이 예상대로 작동하지 않음을 알고 있어야합니다 . 호출자가 버퍼를 전달하도록하면 스토리지 요구 사항이 명시됩니다. 호출자가 실제로 원하는 경우 정적 버퍼를 자유롭게 사용할 수 있으며 동일한 버퍼의 재사용이 명시 적입니다. 또한 최신 PIC ABI에서 정적 버퍼는 일반적으로 스택의 버퍼보다 ​​액세스하는 데 더 많은 코드가 필요합니다.
R .. GitHub 중지 지원 얼음

8
여전히 나쁜 디자인입니다. 이 경우 추가 복사 단계 가 필요하며 복사가 필요하지 않은 경우에도 호출자가 버퍼를 제공하는 것 보다 비싸지 않습니다. 정적 저장소를 사용하는 것은 나쁜 관용구입니다.
R .. GitHub 중지 지원 얼음

3
모든 호출자 가 할당해야하는 스토리지의 크기를 적절하게 조정하고 모든 호출자가이 값을 알고 필요한 양을 할당하도록 강제 하는 데 사용되어야하는 불필요한 추가 이름으로 전 처리기 또는 변수 기호 테이블의 네임 스페이스를 오염시켜야합니다. 단순한 함수 로컬 스토리지 솔루션이 대부분의 의도와 목적에 충분하고 단순한 strdup () 호출이 나머지 사용의 99 %를 차지할 경우 스토리지는 잘못된 설계입니다.
Greg A. Woods 1

5
여기서 우리는 동의하지 않을 것입니다. 사용 사례를 심각하게 제한하고, 인터페이스 오류가 발생하기 쉬우 며, 프로그램 기간 동안 영구 저장 장치를 임시 값으로 임시 값으로 예약하고, 대부분의 경우 더 나쁜 코드를 생성하는 데 악영향을 미치는 주변에 하나의 눈에 거슬리지 않는 전 처리기 기호를 추가하는 방법을 알 수 없습니다. 현대적인 플랫폼.
R .. GitHub 중지 지원 얼음

5
나는 이유없이 측정하는 마이크로 최적화를 옹호하지 않습니다. 그러나 나는 마이크로 게인 규모에 있더라도 기본적으로 우수한 디자인과 함께 보너스로 올 때 언급 할 가치가 있다고 생각합니다.
R .. GitHub 중지 지원 얼음

13
const char* byte_to_binary( int x )
{
    static char b[sizeof(int)*8+1] = {0};
    int y;
    long long z;
    for (z=1LL<<sizeof(int)*8-1,y=0; z>0; z>>=1,y++)
    {
        b[y] = ( ((x & z) == z) ? '1' : '0');
    }

    b[y] = 0;

    return b;
}

6
선명하게 당신이 사용하는 경우 '1''0'대신 4948당신의 삼항에. 또한 b마지막 문자가 널 종료 자로 남아있을 수 있도록 9 자 길이 여야합니다.
tomlogic

또한 매번 B를 초기화해야합니다.
EvilTeach

2
일부를 변경하지 않은 경우 : 1. 최종 0을위한 공간을 추가하십시오. static char b[9] = {0}2. 루프 밖으로 선언을 이동 int z,y;하십시오 . 3. 최종 0을 추가하십시오 b[y] = 0. 이런 식으로 재 초기화가 필요하지 않습니다.
Kobor42

1
좋은 해결책. 그래도 물건을 바꿀 것입니다. 즉, 모든 크기의 입력을 올바르게 처리 할 수 ​​있도록 문자열로 되돌아갑니다.
Kobor42

모든 8을로 교체해야합니다 CHAR_BIT.
alk

12

빠르고 쉬운 솔루션 :

void printbits(my_integer_type x)
{
    for(int i=sizeof(x)<<3; i; i--)
        putchar('0'+((x>>(i-1))&1));
}

모든 크기 유형과 부호있는 및 부호없는 정수에 사용할 수 있습니다. '& 1'은 시프트가 부호 확장을 할 수 있으므로 부호있는 정수를 처리하는 데 필요합니다.

이를 수행하는 방법에는 여러 가지가 있습니다. 부호있는 또는 부호없는 32 비트 유형 (부호가있는 경우 음수를 넣지 않고 실제 비트 만 인쇄)에서 캐리지 리턴이없는 32 비트 또는 n 비트를 인쇄하는 매우 간단한 방법입니다. 비트 시프트 전에 i가 감소합니다.

#define printbits_n(x,n) for (int i=n;i;i--,putchar('0'|(x>>i)&1))
#define printbits_32(x) printbits_n(x,32)

나중에 저장하거나 인쇄 할 비트가 포함 된 문자열을 반환하는 것은 어떻습니까? 메모리를 할당하고 반환 할 수 있으며 사용자가 메모리를 해제해야합니다. 그렇지 않으면 정적 문자열을 반환하지만 다시 호출하거나 다른 스레드에 의해 클러버가 발생합니다. 표시된 두 가지 방법 :

char *int_to_bitstring_alloc(int x, int count)
{
    count = count<1 ? sizeof(x)*8 : count;
    char *pstr = malloc(count+1);
    for(int i = 0; i<count; i++)
        pstr[i] = '0' | ((x>>(count-1-i))&1);
    pstr[count]=0;
    return pstr;
}

#define BITSIZEOF(x)    (sizeof(x)*8)

char *int_to_bitstring_static(int x, int count)
{
    static char bitbuf[BITSIZEOF(x)+1];
    count = (count<1 || count>BITSIZEOF(x)) ? BITSIZEOF(x) : count;
    for(int i = 0; i<count; i++)
        bitbuf[i] = '0' | ((x>>(count-1-i))&1);
    bitbuf[count]=0;
    return bitbuf;
}

전화 :

// memory allocated string returned which needs to be freed
char *pstr = int_to_bitstring_alloc(0x97e50ae6, 17);
printf("bits = 0b%s\n", pstr);
free(pstr);

// no free needed but you need to copy the string to save it somewhere else
char *pstr2 = int_to_bitstring_static(0x97e50ae6, 17);
printf("bits = 0b%s\n", pstr2);

10

이전에 게시 된 답변 중 어느 것도 내가 찾던 것이 아니므로 하나를 썼습니다. 와 함께 % B를 사용하는 것은 매우 간단합니다 printf!

    /*
     * File:   main.c
     * Author: Techplex.Engineer
     *
     * Created on February 14, 2012, 9:16 PM
     */

    #include <stdio.h>
    #include <stdlib.h>
    #include <printf.h>
    #include <math.h>
    #include <string.h>


    static int printf_arginfo_M(const struct printf_info *info, size_t n, int *argtypes) {
        /* "%M" always takes one argument, a pointer to uint8_t[6]. */
        if (n > 0) {
            argtypes[0] = PA_POINTER;
        }
        return 1;
    } /* printf_arginfo_M */

    static int printf_output_M(FILE *stream, const struct printf_info *info, const void *const *args) {
        int value = 0;
        int len;

        value = *(int **) (args[0]);

        //Beginning of my code ------------------------------------------------------------
        char buffer [50] = ""; //Is this bad?
        char buffer2 [50] = ""; //Is this bad?
        int bits = info->width;
        if (bits <= 0)
            bits = 8; // Default to 8 bits

        int mask = pow(2, bits - 1);
        while (mask > 0) {
            sprintf(buffer, "%s", (((value & mask) > 0) ? "1" : "0"));
            strcat(buffer2, buffer);
            mask >>= 1;
        }
        strcat(buffer2, "\n");
        // End of my code --------------------------------------------------------------
        len = fprintf(stream, "%s", buffer2);
        return len;
    } /* printf_output_M */

    int main(int argc, char** argv) {

        register_printf_specifier('B', printf_output_M, printf_arginfo_M);

        printf("%4B\n", 65);

        return (EXIT_SUCCESS);
    }

1
50 비트 이상으로 오버플로됩니까?
Janus Troelsen

좋은 전화, 그래 .. 내가 malloc을 사용해야한다는 말을 들었어?
TechplexEngineer

네 물론 이죠 char* buffer = (char*) malloc(sizeof(char) * 50);
Janus Troelsen

@JanusTroelsen 또는 훨씬 더 깨끗하고 작으며 유지 관리 가능 :char *buffer = malloc(sizeof(*buffer) * 50);
Shahbaz

이 점에서 "% B"가 "% b"와 다른 이유는 무엇입니까? 이전 답변에 따르면 "C 표준 라이브러리에는 바이너리를 출력하는 형식 기능이 없습니다." " 일부 런타임은"% b "를 지원하지만 표준이 아닙니다." .
Peter Mortensen


7

이 코드는 최대 64 비트의 요구를 처리해야합니다. pBin & pBinFill이라는 2 개의 함수를 만들었습니다. 둘 다 동일한 작업을 수행하지만 pBinFill은 선행 공백을 fillChar로 채 웁니다. 테스트 기능은 일부 테스트 데이터를 생성 한 다음이 기능을 사용하여 인쇄합니다.



char* pBinFill(long int x,char *so, char fillChar); // version with fill
char* pBin(long int x, char *so);                   // version without fill
#define kDisplayWidth 64

char* pBin(long int x,char *so)
{
 char s[kDisplayWidth+1];
 int  i=kDisplayWidth;
 s[i--]=0x00;   // terminate string
 do
 { // fill in array from right to left
  s[i--]=(x & 1) ? '1':'0';  // determine bit
  x>>=1;  // shift right 1 bit
 } while( x > 0);
 i++;   // point to last valid character
 sprintf(so,"%s",s+i); // stick it in the temp string string
 return so;
}

char* pBinFill(long int x,char *so, char fillChar)
{ // fill in array from right to left
 char s[kDisplayWidth+1];
 int  i=kDisplayWidth;
 s[i--]=0x00;   // terminate string
 do
 { // fill in array from right to left
  s[i--]=(x & 1) ? '1':'0';
  x>>=1;  // shift right 1 bit
 } while( x > 0);
 while(i>=0) s[i--]=fillChar;    // fill with fillChar 
 sprintf(so,"%s",s);
 return so;
}

void test()
{
 char so[kDisplayWidth+1]; // working buffer for pBin
 long int val=1;
 do
 {
   printf("%ld =\t\t%#lx =\t\t0b%s\n",val,val,pBinFill(val,so,'0'));
   val*=11; // generate test data
 } while (val < 100000000);
}

Output:
00000001 =  0x000001 =  0b00000000000000000000000000000001
00000011 =  0x00000b =  0b00000000000000000000000000001011
00000121 =  0x000079 =  0b00000000000000000000000001111001
00001331 =  0x000533 =  0b00000000000000000000010100110011
00014641 =  0x003931 =  0b00000000000000000011100100110001
00161051 =  0x02751b =  0b00000000000000100111010100011011
01771561 =  0x1b0829 =  0b00000000000110110000100000101001
19487171 = 0x12959c3 =  0b00000001001010010101100111000011

1
"#define width 64"는 log4cxx의 stream.h와 충돌합니다. 기존의 무작위 정의 이름을 사용하십시오 :)
kagali-san

5
@ mhambra : width대신 일반적인 이름을 사용하기 위해 log4cxx에게 알려 주어야 합니다!
u0b34a0f6ae

7

이진 형식으로 인쇄 할 printf 변환기가 있습니까?

printf()제품군은 표준 지정자를 사용하여 8, 10 및 16 기반으로 만 인쇄 할 수 있습니다. 코드의 특정 요구에 따라 숫자를 문자열로 변환하는 함수를 만드는 것이 좋습니다.


베이스에 인쇄하려면 [2-36]

지금까지 다른 모든 답변에는 이러한 제한 중 하나 이상이 있습니다.

  1. 리턴 버퍼에 정적 메모리를 사용하십시오. 이것은 함수가에 대한 인수로 사용될 수있는 횟수를 제한합니다 printf().

  2. 포인터를 비우려면 호출 코드가 필요한 메모리를 할당하십시오.

  3. 적절한 버퍼를 명시 적으로 제공하려면 호출 코드가 필요합니다.

  4. printf()직접 전화하십시오 . 이것은을위한 새로운 기능 의무화 fprintf(), sprintf(), vsprintf(), 등

  5. 감소 된 정수 범위를 사용하십시오.

다음은 위의 제한이 없습니다 . C99 이상이 필요합니다 "%s". 이것은 사용하는 화합물 리터럴 버퍼 공간을 제공 할 수있다. 의 여러 통화에는 문제가 없습니다 printf().

#include <assert.h>
#include <limits.h>
#define TO_BASE_N (sizeof(unsigned)*CHAR_BIT + 1)

//                               v. compound literal .v
#define TO_BASE(x, b) my_to_base((char [TO_BASE_N]){""}, (x), (b))

// Tailor the details of the conversion function as needed
// This one does not display unneeded leading zeros
// Use return value, not `buf`
char *my_to_base(char *buf, unsigned i, int base) {
  assert(base >= 2 && base <= 36);
  char *s = &buf[TO_BASE_N - 1];
  *s = '\0';
  do {
    s--;
    *s = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"[i % base];
    i /= base;
  } while (i);

  // Could employ memmove here to move the used buffer to the beginning

  return s;
}

#include <stdio.h>
int main(void) {
  int ip1 = 0x01020304;
  int ip2 = 0x05060708;
  printf("%s %s\n", TO_BASE(ip1, 16), TO_BASE(ip2, 16));
  printf("%s %s\n", TO_BASE(ip1, 2), TO_BASE(ip2, 2));
  puts(TO_BASE(ip1, 8));
  puts(TO_BASE(ip1, 36));
  return 0;
}

산출

1020304 5060708
1000000100000001100000100 101000001100000011100001000
100401404
A2F44

이것은 매우 유용합니다. C ++에서 사용하는 방법을 알고 있습니까? 컴파일 할 때 "심각도 코드 설명 프로젝트 파일 행 억제 상태 오류 C4576"괄호로 묶은 유형 뒤에 이니셜 라이저 목록이 비표준 명시 적 유형 변환 구문 hello C : \ my_projects \ hello \ hello \ main.cpp 39 "
단지 학습자

1
@Justalearner C ++의 일부가 아닌 C 기능 복합 리터럴 을 사용하는 경우 C ++을 생성합니다 . 아마도 불완전하더라도 시도를 먼저 보여 주면 도움을 얻을 수 있다고 확신하는 C ++ 구현을 게시 할 것입니다.
chux-복원 Monica Monica

6

약간 OT 일 수도 있지만 수행중인 바이너리 작업을 이해하거나 추적하기 위해 디버깅에만 필요하면 wcalc (간단한 콘솔 계산기)를 살펴보십시오. -b 옵션을 사용하면 이진 출력이 나타납니다.

예 :

$ wcalc -b "(256 | 3) & 0xff"
 = 0b11

1
이 전면에 몇 가지 다른 옵션이 있습니다, 너무 ... ruby -e 'printf("%b\n", 0xabc)', dc다음에 2o다음 0x123p등합니다.
lindes

6

C 표준 라이브러리에는 바이너리를 출력하는 형식 지정 기능이 없습니다. printf 제품군이 지원하는 모든 형식 작업은 사람이 읽을 수있는 텍스트를 대상으로합니다.


5

다음과 같은 재귀 함수가 유용 할 수 있습니다.

void bin(int n)
{
    /* Step 1 */
    if (n > 1)
        bin(n/2);
    /* Step 2 */
    printf("%d", n % 2);
}

7
음의 정수에서는 작동하지 않습니다.
앤더슨 프라이 타스

4

크기와 C ++에 대한 최고의 솔루션을 최적화 하고이 솔루션에 도달했습니다.

inline std::string format_binary(unsigned int x)
{
    static char b[33];
    b[32] = '\0';

    for (int z = 0; z < 32; z++) {
        b[31-z] = ((x>>z) & 0x1) ? '1' : '0';
    }

    return b;
}

3
를 통해 동적 메모리를 사용하려는 경우 배열을 std::string제거 할 수도 있습니다 static. 가장 간단한 방법은 static한정자를 삭제 b하고 함수에 로컬로 만드는 것 입니다.
Shahbaz

((x>>z) & 0x01) + '0'충분하다.
Jason C

4

적은 코드와 리소스를 사용하여 모든 유형의 비트 인쇄

이 접근법은 다음과 같은 속성을 갖습니다.

  • 변수 및 리터럴과 함께 작동합니다.
  • 필요하지 않은 경우 모든 비트를 반복하지 않습니다.
  • 바이트를 완료 할 때만 printf를 호출하십시오 (모든 비트에 대해 불필요하지는 않음).
  • 모든 유형에 적용됩니다.
  • 작고 큰 엔디안으로 작동합니다 (확인을 위해 GCC #defines 사용).
  • C 표준은 아니지만 크게 정의 된 typeof ()를 사용합니다.
#include <stdio.h>
#include <stdint.h>
#include <string.h>

#if __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__
#define for_endian(size) for (int i = 0; i < size; ++i)
#elif __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__
#define for_endian(size) for (int i = size - 1; i >= 0; --i)
#else
#error "Endianness not detected"
#endif

#define printb(value)                                   \
({                                                      \
        typeof(value) _v = value;                       \
        __printb((typeof(_v) *) &_v, sizeof(_v));       \
})

void __printb(void *value, size_t size)
{
        uint8_t byte;
        size_t blen = sizeof(byte) * 8;
        uint8_t bits[blen + 1];

        bits[blen] = '\0';
        for_endian(size) {
                byte = ((uint8_t *) value)[i];
                memset(bits, '0', blen);
                for (int j = 0; byte && j < blen; ++j) {
                        if (byte & 0x80)
                                bits[j] = '1';
                        byte <<= 1;
                }
                printf("%s ", bits);
        }
        printf("\n");
}

int main(void)
{
        uint8_t c1 = 0xff, c2 = 0x44;
        uint8_t c3 = c1 + c2;

        printb(c1);
        printb((char) 0xff);
        printb((short) 0xff);
        printb(0xff);
        printb(c2);
        printb(0x44);
        printb(0x4411ff01);
        printb((uint16_t) c3);
        printf("\n");

        return 0;
}

산출

$ ./printb 
11111111 
11111111 
00000000 11111111 
00000000 00000000 00000000 11111111 
01000100 
00000000 00000000 00000000 01000100 
01000100 00010001 11111111 00000001 
00000000 01000011 

내가 사용한 또 다른 접근 방식 ( bitprint.h을 (비트 문자열로) 모든 바이트있는 테이블을 작성하고 입력 / 인덱스 바이트에 기반을 인쇄). 살펴볼 가치가 있습니다.


4
void
print_binary(unsigned int n)
{
    unsigned int mask = 0;
    /* this grotesque hack creates a bit pattern 1000... */
    /* regardless of the size of an unsigned int */
    mask = ~mask ^ (~mask >> 1);

    for(; mask != 0; mask >>= 1) {
        putchar((n & mask) ? '1' : '0');
    }

}

또는 문자 값 '0'에 0 또는 1을 추가하십시오.;) 삼항이 필요하지 않습니다.
Owl

3

paniq의 코드가 마음에 들었습니다. 정적 버퍼는 좋은 생각입니다. 그러나 단일 printf ()에서 여러 이진 형식을 원할 경우 항상 동일한 포인터를 반환하고 배열을 덮어 쓰므로 실패합니다.

다음은 스플릿 버퍼에서 포인터를 회전시키는 C 스타일 드롭 인입니다.

char *
format_binary(unsigned int x)
{
    #define MAXLEN 8 // width of output format
    #define MAXCNT 4 // count per printf statement
    static char fmtbuf[(MAXLEN+1)*MAXCNT];
    static int count = 0;
    char *b;
    count = count % MAXCNT + 1;
    b = &fmtbuf[(MAXLEN+1)*count];
    b[MAXLEN] = '\0';
    for (int z = 0; z < MAXLEN; z++) { b[MAXLEN-1-z] = ((x>>z) & 0x1) ? '1' : '0'; }
    return b;
}

1
일단 count도달 MAXCNT - 1,의 다음 증분은 count그것을 만들 것입니다 MAXCNT배열의 경계 밖으로 액세스의 원인이되는 대신 제로의. 당신은해야합니다 count = (count + 1) % MAXCNT.
Shahbaz

1
그건 그렇고, 나중에이 MAXCNT + 1함수에 대한 호출을 사용하는 개발자에게는 놀라운 일이 될 것 printf입니다. 일반적으로 둘 이상의 옵션을 제공하려면 무한대로 만드십시오. 4와 같은 숫자는 문제를 일으킬 수 있습니다.
Shahbaz

3

표준적이고 휴대용 방식이 없습니다.

일부 구현은 itoa ()를 제공 하지만 대부분은 아니고 다소 거친 인터페이스를 가지고 있습니다. 그러나 코드는 링크 뒤에 있으며 자체 포맷터를 매우 쉽게 구현할 수 있어야합니다.


3

표준 라이브러리를 사용하여 모든 정수 유형 을 이진 문자열 표현으로 변환하는 하나의 명령문 일반 변환 :

#include <bitset>
MyIntegralType  num = 10;
print("%s\n",
    std::bitset<sizeof(num) * 8>(num).to_string().insert(0, "0b").c_str()
); // prints "0b1010\n"

아니면 그냥 : std::cout << std::bitset<sizeof(num) * 8>(num);


1
이것이 C ++의 관용적 솔루션이지만 C를 요구했습니다.
danijar

3

내 해결책 :

long unsigned int i;
for(i = 0u; i < sizeof(integer) * CHAR_BIT; i++) {
    if(integer & LONG_MIN)
        printf("1");
    else
        printf("0");
    integer <<= 1;
}
printf("\n");

3

그의 대답에 @ ideasman42의 제안을 바탕으로,이 제공하는 매크로이다 int8, 16, 3264재사용 버전 INT8피하기 반복에 매크로를.

/* --- PRINTF_BYTE_TO_BINARY macro's --- */
#define PRINTF_BINARY_SEPARATOR
#define PRINTF_BINARY_PATTERN_INT8 "%c%c%c%c%c%c%c%c"
#define PRINTF_BYTE_TO_BINARY_INT8(i)    \
    (((i) & 0x80ll) ? '1' : '0'), \
    (((i) & 0x40ll) ? '1' : '0'), \
    (((i) & 0x20ll) ? '1' : '0'), \
    (((i) & 0x10ll) ? '1' : '0'), \
    (((i) & 0x08ll) ? '1' : '0'), \
    (((i) & 0x04ll) ? '1' : '0'), \
    (((i) & 0x02ll) ? '1' : '0'), \
    (((i) & 0x01ll) ? '1' : '0')

#define PRINTF_BINARY_PATTERN_INT16 \
    PRINTF_BINARY_PATTERN_INT8               PRINTF_BINARY_SEPARATOR              PRINTF_BINARY_PATTERN_INT8
#define PRINTF_BYTE_TO_BINARY_INT16(i) \
    PRINTF_BYTE_TO_BINARY_INT8((i) >> 8),   PRINTF_BYTE_TO_BINARY_INT8(i)
#define PRINTF_BINARY_PATTERN_INT32 \
    PRINTF_BINARY_PATTERN_INT16              PRINTF_BINARY_SEPARATOR              PRINTF_BINARY_PATTERN_INT16
#define PRINTF_BYTE_TO_BINARY_INT32(i) \
    PRINTF_BYTE_TO_BINARY_INT16((i) >> 16), PRINTF_BYTE_TO_BINARY_INT16(i)
#define PRINTF_BINARY_PATTERN_INT64    \
    PRINTF_BINARY_PATTERN_INT32              PRINTF_BINARY_SEPARATOR              PRINTF_BINARY_PATTERN_INT32
#define PRINTF_BYTE_TO_BINARY_INT64(i) \
    PRINTF_BYTE_TO_BINARY_INT32((i) >> 32), PRINTF_BYTE_TO_BINARY_INT32(i)
/* --- end macros --- */

#include <stdio.h>
int main() {
    long long int flag = 1648646756487983144ll;
    printf("My Flag "
           PRINTF_BINARY_PATTERN_INT64 "\n",
           PRINTF_BYTE_TO_BINARY_INT64(flag));
    return 0;
}

이 결과는 다음과 같습니다.

My Flag 0001011011100001001010110111110101111000100100001111000000101000

가독성을 위해 당신은 변경할 수 있습니다 #define PRINTF_BINARY_SEPARATOR#define PRINTF_BINARY_SEPARATOR ","#define PRINTF_BINARY_SEPARATOR " "

출력됩니다 :

My Flag 00010110,11100001,00101011,01111101,01111000,10010000,11110000,00101000

또는

My Flag 00010110 11100001 00101011 01111101 01111000 10010000 11110000 00101000

이 코드를 복사 해 주셔서 감사합니다.이 프로젝트에서 가장 먼저 복사 할 코드는 지루한 작업처럼 느껴졌습니다. :)
DevZer0


2
void print_ulong_bin(const unsigned long * const var, int bits) {
        int i;

        #if defined(__LP64__) || defined(_LP64)
                if( (bits > 64) || (bits <= 0) )
        #else
                if( (bits > 32) || (bits <= 0) )
        #endif
                return;

        for(i = 0; i < bits; i++) { 
                printf("%lu", (*var >> (bits - 1 - i)) & 0x01);
        }
}

작동해야합니다-테스트되지 않았습니다.


2
/* Convert an int to it's binary representation */

char *int2bin(int num, int pad)
{
 char *str = malloc(sizeof(char) * (pad+1));
  if (str) {
   str[pad]='\0';
   while (--pad>=0) {
    str[pad] = num & 1 ? '1' : '0';
    num >>= 1;
   }
  } else {
   return "";
  }
 return str;
}

/* example usage */

printf("The number 5 in binary is %s", int2bin(5, 4));
/* "The number 5 in binary is 0101" */

4
잘못된 비용을 지불하면 성능이 저하됩니다. 버퍼의 파괴에 대한 책임을 발신자에게 전달하는 것은 불친절합니다.
EvilTeach

2

다음은 메모리 레이아웃을 보여줍니다.

#include <limits>
#include <iostream>
#include <string>

using namespace std;

template<class T> string binary_text(T dec, string byte_separator = " ") {
    char* pch = (char*)&dec;
    string res;
    for (int i = 0; i < sizeof(T); i++) {
        for (int j = 1; j < 8; j++) {
            res.append(pch[i] & 1 ? "1" : "0");
            pch[i] /= 2;
        }
        res.append(byte_separator);
    }
    return res;
}

int main() {
    cout << binary_text(5) << endl;
    cout << binary_text(.1) << endl;

    return 0;
}

"다음은 메모리 레이아웃을 보여줄 것" 이란 무엇입니까 ?
Peter Mortensen

2

다음은 템플릿을 사용하여 32 및 64 비트 정수를 인쇄 할 수 있는 paniq 솔루션 의 작은 변형입니다 .

template<class T>
inline std::string format_binary(T x)
{
    char b[sizeof(T)*8+1] = {0};

    for (size_t z = 0; z < sizeof(T)*8; z++)
        b[sizeof(T)*8-1-z] = ((x>>z) & 0x1) ? '1' : '0';

    return std::string(b);
}

다음과 같이 사용할 수 있습니다.

unsigned int value32 = 0x1e127ad;
printf( "  0x%x: %s\n", value32, format_binary(value32).c_str() );

unsigned long long value64 = 0x2e0b04ce0;
printf( "0x%llx: %s\n", value64, format_binary(value64).c_str() );

결과는 다음과 같습니다.

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