Есть ли конвертер printf для печати в двоичном формате? - PullRequest
383 голосов
/ 22 сентября 2008

Я могу печатать с printf как шестнадцатеричное или восьмеричное число. Есть ли тег формата для печати в двоичном или произвольном виде?

Я использую gcc.

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

Ответы [ 48 ]

8 голосов
/ 22 сентября 2008

Некоторые среды выполнения поддерживают "% b", хотя это не стандарт.

Также смотрите здесь для интересного обсуждения:

http://bytes.com/forum/thread591027.html

НТН

7 голосов
/ 03 июля 2009

Этот код должен обрабатывать ваши потребности до 64 бит. Я создал 2 функции pBin & pBinFill. Оба делают одно и то же, но 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 &gt 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
6 голосов
/ 22 сентября 2008

Может быть, немного OT, но если вам нужно это только для отладки, чтобы понять или отследить некоторые выполняемые вами двоичные операции, вы можете взглянуть на wcalc (простой консольный калькулятор). С опциями -b вы получаете двоичный вывод.

, например

$ wcalc -b "(256 | 3) & 0xff"
 = 0b11
6 голосов
/ 22 сентября 2008

В стандартной библиотеке C нет функции форматирования для вывода подобного двоичного файла. Все операции форматирования, поддерживаемые семейством printf, направлены на читабельный текст.

5 голосов
/ 01 марта 2015

Может быть полезна следующая рекурсивная функция:

void bin(int n)
{
    /* Step 1 */
    if (n > 1)
        bin(n/2);
    /* Step 2 */
    printf("%d", n % 2);
}
5 голосов
/ 06 января 2016

Есть ли конвертер 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
4 голосов
/ 12 мая 2018
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');
    }

}
4 голосов
/ 17 июля 2011

Я оптимизировал лучшее решение для размера и 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 голосов
/ 21 августа 2011

Мне понравился код от 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;
}
3 голосов
/ 21 июля 2017

Основываясь на предложении @ ideasman42 в своем ответе, этот макрос предоставляет версии int8, 16, 32 & 64, повторно используя макрос 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
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...