Есть ли конвертер printf для печати в двоичном формате?

357

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

Я запускаю gcc.

printf("%d %x %o\n", 10, 10, 10); //prints "10 A 12\n"
print("%b\n", 10); // prints "%b\n"
  • 0
    Вы не можете сделать это, насколько я знаю, используя printf. Очевидно, что вы могли бы написать вспомогательный метод для достижения этой цели, но это не похоже на направление, в котором вы хотите идти.
  • 0
    Для этого не существует предопределенного формата. Вам необходимо преобразовать его в строку, а затем распечатать строку.
Показать ещё 4 комментария
Теги:
printf

48 ответов

213

Хакки, но работает для меня:

#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 в некоторых других предложениях здесь.

  • 11
    И имеет преимущество в том, что он может вызываться несколько раз в printf чего не могут делать те, у кого есть static буферы.
  • 3
    Я позволил себе сменить %d на %c , потому что он должен быть еще быстрее ( %d должен выполнить преобразование цифр-> символов, в то время как %c просто выводит аргумент
Показать ещё 5 комментариев
181

Печать двоичного кода для любого типа данных

//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;
}
  • 0
    Просто вау, использовал это некоторое время сейчас в разных случаях, и это работает каждый раз
  • 8
    Предложить size_t i; for (i=size; i-- > 0; ) чтобы избежать size_t i; for (i=size; i-- > 0; ) size_t и int .
Показать ещё 6 комментариев
156

Вот быстрый хак, чтобы продемонстрировать методы, чтобы делать то, что вы хотите.

#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;
}
  • 0
    Добро пожаловать. Спасибо за голосование.
  • 2
    Это, конечно, менее «странно», чем обычная запись escape-перегрузки для printf. Это также легко понять для разработчика, не знакомого с кодом.
Показать ещё 12 комментариев
73

В glibc обычно нет спецификатора двоичного преобразования.

Можно добавить собственные типы конверсий в семейство функций printf() в glibc. Подробнее см. register_printf_function. Вы можете добавить пользовательское преобразование% b для собственного использования, если оно упростит код приложения, чтобы он был доступен.

Вот пример о том, как реализовать пользовательские форматы printf в glibc.

  • 0
    Я всегда писал свой собственный v [snf] printf () для ограниченных случаев, когда мне нужны были разные радиксы: я так рад, что просмотрел это.
26

Вы можете использовать небольшую таблицу для повышения скорости 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 В основном я имею в виду встроенные приложения, в которых оптимизаторы не так агрессивны и разница в скорости видима.

  • 3
    Отличный ответ, очень простой для понимания в своей простоте и явный победитель для небольших встроенных систем.
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 и 10, если вы просто замените 2 на нужную базу. Использование:

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

Где x - любое интегральное выражение.

  • 1
    Если вы не беспокоитесь о повторном входе, тогда вы можете избавиться от необходимости макроса или константы, определяющей размер буфера, и необходимости сделать эту константу видимой для всех вызывающих, и, конечно же, второго параметра, возвращающего указатель на функционально-локальный статический массив.
  • 5
    Да, вы можете сделать это. Но это действительно плохой дизайн. Даже если у вас нет потоков или повторного входа, вызывающая char *a = binary_fmt(x), *b = binary_fmt(y); должна знать, что статический буфер используется повторно и что такие вещи, как char *a = binary_fmt(x), *b = binary_fmt(y); не будет работать, как ожидалось. Принуждение вызывающей стороны к пропуску буфера приводит к требованию хранения; вызывающий, конечно, может свободно использовать статический буфер, если это действительно необходимо, и тогда повторное использование этого же буфера становится явным. Также обратите внимание, что в современных PIC ABI статические буферы обычно требуют больше кода для доступа, чем буферы в стеке.
Показать ещё 14 комментариев
15

На основе ответа @William Whyte это макрос, который предоставляет версии int8, 16, 32 и 64, повторно используя макрос int8, чтобы избежать повторения.

/* --- PRINTF_BYTE_TO_BINARY macro --- */
#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
  • 0
    Это отлично. Есть ли особая причина для печати битов, начинающихся с наименее значимых бит?
  • 1
    @SilentMonk спасибо, исправлено, также добавлен 64-битный макрос.
Показать ещё 2 комментария
14

Распечатайте младший бит и сдвиньте его справа. Выполняя это до тех пор, пока целое число не станет равным нулю, печатает двоичное представление без начальных нулей, но в обратном порядке. Используя рекурсию, порядок можно легко скорректировать.

#include <stdio.h>

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

Для меня это одно из самых чистых решений проблемы. Если вам нравится префикс 0b и новый новый символ строки, я предлагаю обернуть функцию.

Демо-версия онлайн

  • 0
    ошибка: слишком мало аргументов для вызова функции, ожидается 2, есть 1 putc ((число & 1)? '1': '0');
  • 0
    @KorayTugay Спасибо за указание на это. Я исправил вызов функции и добавил демо.
Показать ещё 1 комментарий
11
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' вместо 49 и 48 в своей троице. Кроме того, b должно быть длиной 9 символов, чтобы последний символ оставался нулевым терминатором.
  • 0
    Также B необходимо каждый раз инициализировать.
Показать ещё 3 комментария
8

Ни один из ранее опубликованных ответов не является тем, что я искал, поэтому я написал один. Очень просто использовать% 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 битами?
  • 0
    Хороший вызов, да, это будет ... Мне сказали, что мне нужно использовать malloc, когда-нибудь, понимаешь?
Показать ещё 4 комментария
7

Этот код должен обрабатывать ваши потребности до 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
  • 0
    «#define width 64» конфликтует с stream.h из log4cxx. Пожалуйста, используйте условно случайные определения имен :)
  • 0
    Спасибо, Мамбра, это очень хороший момент.
Показать ещё 1 комментарий
7

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

Также см. Здесь интересную дискуссию:

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

НТН

  • 1
    На самом деле это свойство библиотеки времени выполнения C, а не компилятора.
5

Есть ли конвертер 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
5

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

void bin(int n)
{
    /* Step 1 */
    if (n > 1)
        bin(n/2);
    /* Step 2 */
    printf("%d", n % 2);
}
  • 6
    Будьте осторожны, это не работает с отрицательными целыми числами.
5

Я оптимизировал верхнее решение для размера и С++ - и нашел это решение:

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;
}
  • 2
    Если вы хотите использовать динамическую память (через std::string ), вы также можете избавиться от static массива. Простейшим способом было бы просто удалить static классификатор и сделать b локальным для функции.
  • 0
    ((x>>z) & 0x01) + '0' достаточно.
5

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

например.

$ wcalc -b "(256 | 3) & 0xff"
 = 0b11
  • 1
    на этом фронте есть и несколько других опций ... ruby -e 'printf("%b\n", 0xabc)' , dc затем 2o затем 0x123p и так далее.
5

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

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 к символьному значению '0';) Троицы не нужны.
3

На основе предложения @ideaman42 в его ответе это макрос, который предоставляет версии int8, 16, 32 и 64, повторно используя макрос int8, чтобы избежать повторения.

/* --- PRINTF_BYTE_TO_BINARY macro --- */
#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
  • 0
    спасибо, что скопировал этот код, первым, кто скопировал в этом проекте, над которым я работаю, написание этого было утомительным занятием :)
3

Печать битов любого типа с использованием меньшего количества кода и ресурсов

Этот подход имеет следующие атрибуты:

  • Работает с переменными и литералами.
  • Не выполняет итерацию всех битов, если это не необходимо.
  • Вызывайте printf только после завершения байта (не обязательно для всех битов).
  • Работает для любого типа.
  • Работает с небольшим и большим контентом (использует проверки GCС#defines для проверки).
  • Использует typeof(), который не является стандартом C, но в значительной степени определяется.
#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), чтобы заполнить таблицу со всеми байтами (как битовые строки) и печатать их на основе байта ввода/индекса. Это стоит взглянуть.

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

Мне понравился код 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 .
  • 1
    Кстати, это станет неожиданностью для разработчика, который использует MAXCNT + 1 для этой функции в одном printf . В общем, если вы хотите предоставить опцию для более чем 1 вещи, сделайте ее бесконечной. Числа, такие как 4, могут только вызвать проблему.
3

Нет стандартного и портативного способа.

Некоторые реализации предоставляют itoa(), но это не будет в большинстве, и у него есть несколько crummy интерфейс. Но код находится за ссылкой и должен позволить вам легко реализовать свой собственный форматировщик.

2

Одно утверждение общего преобразования любого интегрального типа в двоичное строковое представление с использованием стандартной библиотеки:

#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.
2

Небольшая функция полезности в C для этого, решая проблему с небольшим манипуляцией. Это проходит через строку, проверяющую каждый бит набора с использованием маски (1 <

void
printStringAsBinary(char * input)
{
    char * temp = input;
    int i = 7, j =0;;
    int inputLen = strlen(input);

    /* Go over the string, check first bit..bit by bit and print 1 or 0
     **/

    for (j = 0; j < inputLen; j++) {
        printf("\n");
        while (i>=0) {
            if (*temp & (1 << i)) {
               printf("1");
            } else {
                printf("0");
            }
            i--;
        }
        temp = temp+1;
        i = 7;
        printf("\n");
    }
}
2

Вот как я сделал это для unsigned int

void printb(unsigned int v) {
    unsigned int i, s = 1<<((sizeof(v)<<3)-1); // s = only most significant bit at 1
    for (i = s; i; i>>=1) printf("%d", v & i || 0 );
}
  • 0
    Просто заметил, что это очень похоже на решение @Marko
  • 0
    Есть ли способ ограничить размер вывода на выходе?
Показать ещё 1 комментарий
2

Я просто хочу опубликовать свое решение. Он использовал для получения нулей и единиц одного байта, но вызов этой функции несколько раз может быть использован для больших блоков данных. Я использую его для 128-битных или больших структур. Вы также можете изменить его, чтобы использовать size_t в качестве входного параметра и указатель на данные, которые вы хотите распечатать, поэтому он может быть независимым от размера. Но он работает для меня так, как есть.

void print_binary(unsigned char c)
{
 unsigned char i1 = (1 << (sizeof(c)*8-1));
 for(; i1; i1 >>= 1)
      printf("%d",(c&i1)!=0);
}

void get_binary(unsigned char c, unsigned char bin[])
{
 unsigned char i1 = (1 << (sizeof(c)*8-1)), i2=0;
 for(; i1; i1>>=1, i2++)
      bin[i2] = ((c&i1)!=0);
}
2

Еще один подход к печати в двоичном формате: Преобразовать целое число сначала.

Чтобы напечатать 6 в двоичном формате, измените 6 на 110, затем распечатайте "110".

Обходит char buf[] проблемы.
printf() спецификаторы форматирования, флаги и поля, такие как "%08lu", "%*lX", все еще легко доступны.
Не только двоичный (база 2), этот метод расширяется до других оснований до 16.
Ограничено небольшими целыми значениями.

#include <stdint.h>
#include <stdio.h>
#include <inttypes.h>

unsigned long char_to_bin10(char ch) {
  unsigned char uch = ch;
  unsigned long sum = 0;
  unsigned long power = 1;
  while (uch) {
    if (uch & 1) {
      sum += power;
      }
   power *= 10;
   uch /= 2;
  }
  return sum;
}

uint64_t uint16_to_bin16(uint16_t u) {
  uint64_t sum = 0;
  uint64_t power = 1;
  while (u) {
    if (u & 1) {
      sum += power;
      }
    power *= 16;
    u /= 2;
  }
  return sum;
}

void test(void) {
  printf("%lu\n", char_to_bin10(0xF1));
  // 11110001
  printf("%" PRIX64 "\n", uint16_to_bin16(0xF731));
  // 1111011100110001
}
2

Вот небольшая вариация решения paniq, которая использует шаблоны для печати 32 и 64-битных целых чисел:

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
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;
}
  • 0
    Что вы подразумеваете под "Далее покажет вам макет памяти" ?
2
/* Convert an int to it 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
    Оплата стоимости неправильного размещения повредит производительности. Передача ответственности за уничтожение буфера вызывающей стороне недобросовестна.
2
#include <stdio.h>
#include <conio.h>

void main()
{
    clrscr();
    printf("Welcome\n\n\n");
    unsigned char x='A';
    char ch_array[8];
    for(int i=0; x!=0; i++)
    {
        ch_array[i] = x & 1;
        x = x >>1;
    }
    for(--i; i>=0; i--)
        printf("%d", ch_array[i]);

    getch();
}
  • 0
    рекурсия также может быть использована.
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);
        }
}

должен работать - непроверенный.

1
void DisplayBinary(unsigned int n)
{
    int l = sizeof(n) * 8;
    for (int i = l - 1 ; i >= 0; i--) {
        printf("%x", (n & (1 << i)) >> i);
    }
}
  • 0
    Я думаю, что это был большой мозговой штурм, я бы хотел, чтобы авторы Gnu libc выбрали решение, которое им понравилось больше всего, и воплотили его в жизнь. В 2018 году я работаю над отображением двоичных чисел с помощью xlib, двоичный в качестве режима вывода не устареет, пока это режим ввода. И ширина постоянно меняется.
1
void DisplayBinary(int n)
{
    int arr[8];
    int top =-1;
    while (n)
    {
        if (n & 1)
            arr[++top] = 1;
        else
            arr[++top] = 0;

        n >>= 1;
    }
    for (int i = top ; i > -1;i--)
    {
        printf("%d",arr[i]);
    }
    printf("\n");
}
1

Возможно, кто-то найдет это решение полезным:

void print_binary(int number, int num_digits) {
    int digit;
    for(digit = num_digits - 1; digit >= 0; digit--) {
        printf("%c", number & (1 << digit) ? '1' : '0');
    }
}
1

Существует также идея конвертировать число в шестнадцатеричный формат, а затем декодировать каждый шестнадцатеричный шифр на четыре "бита" (единицы и нули). sprintf может выполнять бит для нас:

const char* binary(int n) {
  static const char binnums[16][5] = { "0000","0001","0010","0011",
    "0100","0101","0110","0111","1000","1001","1010","1011","1100","1101","1110","1111" };
  static const char* hexnums = "0123456789abcdef";
  static char inbuffer[16], outbuffer[4*16];
  const char *i;
  sprintf(inbuffer,"%x",n); // hexadecimal n -> inbuffer
  for(i=inbuffer; *i!=0; ++i) { // for each hexadecimal cipher
    int d = strchr(hexnums,*i) - hexnums; // store its decimal value to d
    char* o = outbuffer+(i-inbuffer)*4; // shift four characters in outbuffer
    sprintf(o,"%s",binnums[d]); // place binary value of d there
  }
  return strchr(outbuffer,'1'); // omit leading zeros
}

puts(binary(42)); // outputs 101010
1

Использование:

char buffer [33];
itoa(value, buffer, 2);
printf("\nbinary: %s\n", buffer);

Подробнее см. Как напечатать двоичный номер через printf.

  • 1
    В предыдущем ответе говорилось: «Некоторые реализации предоставляют itoa (), но в большинстве случаев этого не будет» ?
0

Быстрое и простое решение:

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

Работает для любого типа размера и для подписанных и беззнаковых целых. '& 1' необходим для обработки подписанных целых, поскольку сдвиг может расширять подпись.

Есть так много способов сделать это. Здесь супер простой для печати 32 бит или n бит из 32-битного типа со знаком или без знака (не помещая минус, если подписано, просто печатая фактические биты) и без возврата каретки. Обратите внимание, что я уменьшается до сдвига битов:

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

Сделайте функцию и вызовите ее

display_binary(int n)
{
    long int arr[32];
    int arr_counter=0;
    while(n>=1)
    {
        arr[arr_counter++]=n%2;
        n/=2;
    }
    for(int i=arr_counter-1;i>=0;i--)
    {
        printf("%d",arr[i]);
    }
}
0

Используйте функцию ниже:

void conbin(int num){  
        if(num != 0)
        {
            conbin(num >> 1);     
            if (num & 1){
            printf("1");
            }
            else{
            printf("0");
            }
        }
    }
0

Следующая функция возвращает двоичное представление заданного целого числа без знака, используя арифметику указателя без начальных нулей:

const char* toBinaryString(unsigned long num)
{
    static char buffer[CHAR_BIT*sizeof(num)+1];
    char* pBuffer = &buffer[sizeof(buffer)-1];

    do *--pBuffer = '0' + (num & 1);
    while (num >>= 1);
    return pBuffer;
}

Обратите внимание, что нет необходимости в расшифровывании терминатора NUL, поскольку buffer представляет объект со статической продолжительностью хранения, который уже заполнен всеми нулями.

Это может быть легко адаптировано к unsigned long long (или другому целому числу без знака) простым модификацией формального параметра num.

Для CHAR_BIT требуется <limits.h>.

Вот пример использования:

int main(void)
{
    printf(">>>%20s<<<\n", toBinaryString(1));
    printf(">>>%-20s<<<\n", toBinaryString(254));
    return 0;
}

с его желаемым выходом:

>>>                   1<<<
>>>11111110            <<<
  • 1
    Осторожно, это не повторный вход. Плохие вещи могут произойти, если вы попытаетесь использовать его одновременно из двух разных потоков, или если вы сохраните результат и вызовете его снова (второй вызов закроет первый результат).
0
void binario(int num) {
  for(int i=0;i<32;i++){
    (num&(1<i))? printf("1"):
        printf("0");
  }  
  printf("\n");
}
0

Вот очень простой:

int print_char_to_binary(char ch)
{
    int i;
    for (i=7; i>=0; i--)
        printf("%hd ", ((ch & (1<<i))>>i));
    printf("\n");
    return 0;
}
  • 0
    Примечание. Чем полезна буква "h" ? Выглядит одинаково хорошо без него.
  • 0
    @ chux, это не совсем полезно на самом деле. В любом случае, аргумент повышается до int поэтому и %d и %hd должны были бы взять один int из varargs .
Показать ещё 1 комментарий
0

Это может быть не очень эффективно, но это довольно просто. Попробуйте следующее:

tmp1 = 1;
while(inint/tmp1 > 1) {
    tmp1 <<= 1;
}
do {
    printf("%d", tmp2=inint/tmp1);
    inint -= tmp1*tmp2;
} while((tmp1 >>= 1) > 0);
printf(" ");
0

Есть ли конвертер printf для печати в двоичном формате?

Нет стандартного спецификатора формата printf для выполнения "двоичного" вывода. Вот альтернатива, которую я придумал, когда мне это нужно.

Шахта работает для любой базы от 2 до 36. Она вентилирует цифры в вызывающие кадры рекурсивных вызовов, пока не достигнет цифры, меньшей, чем базовая. Затем он "перемещается" назад, заполняя буфер вперед и возвращается. Возвращаемое значение - используемый размер или -1, если буфер недостаточно велик для хранения строки.

int conv_rad (int num, int rad, char *s, int n) {
    char *vec = "0123456789" "ABCDEFGHIJKLM" "NOPQRSTUVWXYZ";
    int off;
    if (n == 0) return 0;
    if (num < rad) { *s = vec[num]; return 1; }
    off = conv_rad(num/rad, rad, s, n);
    if ((off == n) || (off == -1)) return -1;
    s[off] = vec[num%rad];
    return off+1;
}

Одно большое предостережение: эта функция была разработана для использования с строками "Pascal", которые несут свою длину. Следовательно, conv_rad, как написано, не nul-завершает буфер. Для более общих применений C, вероятно, потребуется простая оболочка для nul-terminate. Или для печати просто измените назначения на putchar() s.

0
void PrintBinary( int Value, int Places, char* TargetString)
{
    int Mask;

    Mask = 1 << Places;

    while( Places--) {
        Mask >>= 1; /* Preshift, because we did one too many above */
        *TargetString++ = (Value & Mask)?'1':'0';
    }
    *TargetString = 0; /* Null terminator for C string */
}

Вызывающая функция "владеет" строкой...:

char BinaryString[17];
...
PrintBinary( Value, 16, BinaryString);
printf( "yadda yadda %s yadda...\n", BinaryString);

В зависимости от вашего процессора большинство операций в PrintBinary выдает одно или несколько машинных инструкций.

  • 0
    Это имеет больше смысла, если вы используете do { ... } while ( ... ); и смещение вместо предварительного смещения.
0

Даже для библиотек времени выполнения, поддерживающих% b, кажется, что это только для целых значений.

Если вы хотите печатать значения с плавающей запятой в двоичном формате, я написал код, который вы можете найти в http://www.exploringbinary.com/converting-floating-point-numbers-to-binary-strings-in-c/.

Ещё вопросы

Сообщество Overcoder
Наверх
Меню