Apakah ada konverter printf untuk mencetak dalam format biner?

435

Saya dapat mencetak dengan printf sebagai angka hex atau oktal. Apakah ada tag format untuk dicetak sebagai biner, atau basis arbitrer?

Saya menjalankan gcc.

printf("%d %x %o\n", 10, 10, 10); //prints "10 A 12\n"
print("%b\n", 10); // prints "%b\n"
Brian
sumber
Anda tidak dapat melakukan ini, sejauh yang saya tahu, menggunakan printf. Anda bisa, jelas, menulis metode pembantu untuk mencapai ini, tetapi itu tidak terdengar seperti arah yang ingin Anda tuju.
Ian P
Tidak ada format yang ditentukan untuk itu. Anda perlu mengubahnya sendiri menjadi sebuah string dan kemudian mencetaknya.
rslite
Pencarian Google cepat menghasilkan halaman ini dengan beberapa informasi yang mungkin berguna: forums.macrumors.com/archive/index.php/t-165959.html
Ian P
12
Bukan sebagai bagian dari Perpustakaan C Standar ANSI - jika Anda menulis kode portabel, metode teraman adalah dengan menggulirkan kode Anda sendiri.
tomlogic
Satu pernyataan standar dan generik (untuk semua tipe Integral dengan panjang berapa pun) dari konversi ke string biner di C ++: stackoverflow.com/a/31660310/1814353
luart

Jawaban:

267

Meretas tetapi bekerja untuk saya:

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

Untuk tipe multi-byte

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

Sayangnya, Anda membutuhkan semua kutipan tambahan. Pendekatan ini memiliki risiko efisiensi makro (jangan melewati fungsi sebagai argumen untuk BYTE_TO_BINARY) tetapi menghindari masalah memori dan beberapa pemanggilan strcat dalam beberapa proposal lainnya di sini.

William Whyte
sumber
13
Dan memiliki keuntungan juga menjadi invocable beberapa kali di printfmana yang dengan staticbuffer tidak bisa.
Patrick Schlüter
4
Saya telah mengambil kebebasan untuk mengubah %dke %c, karena harus lebih cepat ( %dharus melakukan konversi digit-> char, sementara %chanya mengeluarkan argumen
3
Diposting versi yang diperluas dari makro ini dengan 16, 32, 64 bit dukungan int: stackoverflow.com/a/25108449/432509
ideasman42
2
Perhatikan bahwa pendekatan ini tidak ramah tumpukan. Dengan asumsi int32-bit pada sistem, mencetak nilai 32-bit tunggal akan membutuhkan ruang untuk nilai 32 * 4-byte; total 128 byte. Yang, tergantung pada ukuran tumpukan, mungkin atau mungkin tidak menjadi masalah.
user694733
1
itu penting untuk menambahkan tanda kurung di sekitar byte di makro atau Anda bisa mengalami masalah saat mengirim operasi BYTE_TO_BINARY (a | b) -> a | b & 0x01! = (a | b) & 0x01
Ivan Hoffmann
203

Cetak Biner untuk Semua Datatype

//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("");
}

uji

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;
}
criptych berdiri bersama Monica
sumber
8
Sarankan size_t i; for (i=size; i-- > 0; )untuk menghindari size_tvs intsalah pertandingan.
chux - Reinstate Monica
1
Bisakah seseorang tolong uraikan logika di balik kode ini?
Juli
2
Ambil setiap byte dalam ptr(loop luar); lalu untuk setiap bit byte saat ini (loop dalam), tutup byte dengan bit saat ini ( 1 << j). Geser ke kanan yang menghasilkan byte yang berisi 0 ( 0000 0000b) atau 1 ( 0000 0001b). Cetak byte printf yang dihasilkan dengan format %u. HTH.
nielsbot
1
@ ZX9 Perhatikan bahwa kode yang disarankan digunakan >dengan size_tdan bukan >=dari komentar Anda untuk menentukan kapan harus mengakhiri loop.
chux - Reinstate Monica
3
@ ZX9 Masih komentar asli Anda yang bermanfaat karena coders harus berhati-hati mengingat penggunaan case tepi >dan >=dengan tipe yang tidak ditandatangani. 0adalah kasus tepi yang tidak ditandatangani dan sering terjadi, tidak seperti matematika yang ditandatangani dengan yang kurang umum INT_MAX/INT_MIN.
chux - Reinstate Monica
151

Berikut ini adalah retasan cepat untuk menunjukkan teknik untuk melakukan apa yang Anda inginkan.

#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;
}
EvilTeach
sumber
2
Ini tentu saja kurang "aneh" dari pada penulisan custom yang overload untuk printf. Sangat mudah dipahami oleh pengembang yang baru mengenal kode ini.
Furious Coder
43
Beberapa perubahan: strcatadalah metode yang tidak efisien untuk menambahkan karakter tunggal ke string pada setiap lintasan loop. Sebagai gantinya, tambahkan char *p = b;dan ganti loop dalam dengan *p++ = (x & z) ? '1' : '0'. zharus dimulai pada 128 (2 ^ 7), bukan 256 (2 ^ 8). Coba perbarui untuk mengambil pointer ke buffer yang akan digunakan (untuk keamanan thread), mirip dengan inet_ntoa().
tomlogic
3
@ EvilTeach: Anda menggunakan operator ternary sendiri sebagai parameter untuk strcat()! Saya setuju bahwa strcatmungkin lebih mudah dipahami daripada menambahkan pointer dereferenced setelah penugasan, tetapi bahkan pemula perlu tahu cara menggunakan perpustakaan standar dengan benar. Mungkin menggunakan array yang diindeks untuk tugas akan menjadi demonstrasi yang baik (dan benar-benar akan berfungsi, karena btidak disetel ulang ke all-nol setiap kali Anda memanggil fungsi).
tomlogic
3
Acak: Arang buffer biner bersifat statis, dan dihapus ke semua nol dalam penugasan. Ini hanya akan menghapusnya saat pertama kali dijalankan, dan setelah itu tidak akan jelas, tetapi sebaliknya menggunakan nilai terakhir.
markwatson
8
Juga, ini harus mendokumentasikan bahwa hasil sebelumnya akan valid setelah memanggil fungsi lagi, sehingga penelepon tidak harus mencoba untuk menggunakannya seperti ini: printf("%s + %s = %s", byte_to_binary(3), byte_to_binary(4), byte_to_binary(3+4)).
Paŭlo Ebermann
84

Biasanya tidak ada specifier konversi biner di glibc.

Dimungkinkan untuk menambahkan jenis konversi khusus ke keluarga fungsi printf () di glibc. Lihat register_printf_fungsi untuk detailnya. Anda dapat menambahkan konversi% b kustom untuk penggunaan Anda sendiri, jika itu menyederhanakan kode aplikasi agar tersedia.

Berikut adalah contoh cara menerapkan format printf kustom di glibc.

DGentry
sumber
Saya selalu menulis sendiri v [snf] printf () saya untuk kasus terbatas di mana saya menginginkan radix yang berbeda: sangat senang saya melihat-lihat ini.
Jamie
3
warning: 'register_printf_function' is deprecated [-Wdeprecated-declarations]Ada fungsi baru untuk melakukan hal yang sama, meskipun: register_printf_specifier(). Contoh penggunaan baru dapat ditemukan di sini: codereview.stackexchange.com/q/219994/200418
Cacahuete Frito
47

Anda bisa menggunakan meja kecil untuk meningkatkan kecepatan 1 . Teknik serupa berguna di dunia tertanam, misalnya, untuk membalikkan byte:

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 Saya kebanyakan mengacu pada aplikasi yang dibenamkan di mana pengoptimal tidak begitu agresif dan perbedaan kecepatan terlihat.

Shahbaz
sumber
27

Cetak bit yang paling tidak signifikan dan geser keluar di sebelah kanan. Melakukan ini sampai bilangan bulat menjadi nol mencetak representasi biner tanpa memimpin nol tetapi dalam urutan terbalik. Menggunakan rekursi, pesanan dapat dikoreksi dengan mudah.

#include <stdio.h>

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

Bagi saya, ini adalah salah satu solusi terbersih untuk masalah ini. Jika Anda menyukai 0bawalan dan karakter baris baru yang tertinggal, saya sarankan membungkus fungsi.

Demo online

danijar
sumber
error: terlalu sedikit argumen yang berfungsi, diharapkan 2, memiliki 1 putc ((nomor & 1)? '1': '0');
Koray Tugay
@ KorayTugay Terima kasih telah menunjukkannya. Saya mengoreksi panggilan fungsi dan menambahkan demo.
danijar
6
Anda juga harus menggunakan nomor int yang tidak ditandatangani, karena ketika nomor yang diberikan negatif, fungsi masuk dalam panggilan rekursif yang tidak pernah berakhir.
Puffy
Pendekatan yang lebih efisien, karena dalam ASCII, '0' + 1 = '1':putc('0'+(number&1), stdout);
Roger Dueck
22

Berdasarkan jawaban @William Whyte, ini adalah makro yang menyediakan int8, 16, 32& 64versi, menggunakan kembali INT8makro untuk menghindari pengulangan.

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

Output ini:

My Flag 0001011011100001001010110111110101111000100100001111000000101000

Untuk keterbacaan, Anda mungkin ingin menambahkan pemisah misalnya:

My Flag 00010110,11100001,00101011,01111101,01111000,10010000,11110000,00101000
gagasanman42
sumber
Ini luar biasa. Apakah ada alasan khusus untuk mencetak bit yang dimulai dengan Least Significant Bits?
gaganso
2
bagaimana Anda merekomendasikan menambahkan koma?
nmz787
Akan menambahkan PRINTF_BYTE_TO_BINARY_INT#definisi yang dikelompokkan untuk digunakan secara opsional.
ideasman42
16

Berikut adalah versi fungsi yang tidak mengalami masalah reentrancy atau batasan ukuran / jenis argumen:

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

Perhatikan bahwa kode ini akan berfungsi dengan baik untuk setiap pangkalan antara 2 dan 10 jika Anda hanya mengganti 2 dengan pangkalan yang diinginkan. Penggunaannya adalah:

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

Di mana xada ekspresi integral.

R .. GitHub BERHENTI MEMBANTU ICE
sumber
7
Ya, Anda bisa melakukannya. Tapi itu desain yang sangat buruk. Bahkan jika Anda tidak memiliki utas atau reentrancy, penelepon harus menyadari bahwa buffer statis sedang digunakan kembali, dan bahwa hal-hal seperti char *a = binary_fmt(x), *b = binary_fmt(y);tidak akan berfungsi seperti yang diharapkan. Memaksa penelepon untuk melewati buffer membuat persyaratan penyimpanannya jelas; penelepon tentu saja bebas menggunakan buffer statis jika itu benar-benar diinginkan, dan kemudian menggunakan kembali buffer yang sama menjadi eksplisit. Juga perhatikan bahwa, pada PIC ABI modern, buffer statis biasanya membutuhkan lebih banyak kode untuk diakses daripada buffer pada stack.
R .. GitHub BERHENTI MEMBANTU ICE
8
Itu masih desain yang buruk. Ini membutuhkan langkah penyalinan tambahan dalam kasus-kasus itu, dan itu tidak lebih murah daripada meminta penelepon menyediakan buffer bahkan dalam kasus-kasus di mana penyalinan tidak diperlukan. Menggunakan penyimpanan statis hanyalah idiom yang buruk.
R .. GitHub BERHENTI MEMBANTU ICE
3
Harus mencemari namespace dari preprocessor atau tabel simbol variabel dengan nama tambahan yang tidak perlu yang harus digunakan untuk ukuran penyimpanan yang harus dialokasikan oleh setiap pemanggil, dan memaksa setiap pemanggil untuk mengetahui nilai ini dan untuk mengalokasikan jumlah yang diperlukan dari penyimpanan, adalah desain yang buruk ketika solusi penyimpanan fungsi-lokal yang lebih sederhana akan mencukupi untuk sebagian besar maksud dan tujuan, dan ketika panggilan strdup () sederhana mencakup 99% dari sisa penggunaan.
Greg A. Woods
5
Di sini kita harus tidak setuju. Saya tidak dapat melihat bagaimana menambahkan satu simbol preprosesor yang tidak mencolok mendekati bahaya membatasi penggunaan kasus-kasus, membuat antarmuka rawan kesalahan, menyimpan penyimpanan permanen selama durasi program untuk nilai sementara, dan menghasilkan kode yang lebih buruk pada sebagian besar platform modern.
R .. GitHub BERHENTI MEMBANTU ICE
5
Saya tidak menganjurkan pengoptimalan mikro tanpa alasan (yaitu pengukuran). Tapi saya pikir kinerja, bahkan jika itu pada skala gain mikro, layak disebut ketika datang sebagai bonus bersama dengan desain yang secara fundamental unggul.
R .. GitHub BERHENTI MEMBANTU ICE
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;
}
DanSkeel
sumber
6
Lebih jelas jika Anda menggunakan '1'dan '0'bukannya 49dan 48di ternary Anda. Juga, bharus sepanjang 9 karakter sehingga karakter terakhir dapat tetap menjadi terminator nol.
tomlogic
Juga B perlu diinisialisasi setiap kali.
EvilTeach
2
Tidak jika Anda mengubah beberapa: 1. ruang add untuk akhir nol: static char b[9] = {0}2. Langkah deklarasi keluar dari loop: int z,y;3. Tambahkan akhir nol: b[y] = 0. Dengan cara ini tidak diperlukan reinitalization.
Kobor42
1
Solusi yang bagus. Saya akan mengubah beberapa hal. Yaitu akan mundur dalam string sehingga input dari berbagai ukuran dapat ditangani dengan benar.
Kobor42
Semua 8itu harus diganti oleh CHAR_BIT.
alk
12

Solusi cepat dan mudah:

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

Bekerja untuk semua jenis ukuran dan untuk int yang ditandatangani dan tidak ditandatangani. Tanda '& 1' diperlukan untuk menangani int yang ditandatangani karena shift mungkin melakukan ekstensi sign.

Ada banyak cara untuk melakukan ini. Inilah yang super sederhana untuk mencetak 32 bit atau n bit dari jenis 32 bit yang ditandatangani atau tidak ditandatangani (tidak menempatkan negatif jika ditandatangani, hanya mencetak bit yang sebenarnya) dan tidak ada carriage return. Perhatikan bahwa saya dikurangi sebelum bit shift:

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

Bagaimana dengan mengembalikan string dengan bit untuk disimpan atau dicetak nanti? Anda dapat mengalokasikan memori dan mengembalikannya dan pengguna harus membebaskannya, atau Anda mengembalikan string statis tetapi itu akan musnah jika dipanggil lagi, atau dengan utas lainnya. Kedua metode yang ditampilkan:

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

Telepon dengan:

// 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);
Robotbugs
sumber
10

Tidak ada jawaban yang diposting sebelumnya persis apa yang saya cari, jadi saya menulis satu. Sangat mudah menggunakan% B dengan 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);
    }
TechplexEngineer
sumber
1
akankah ini meluap dengan lebih dari 50 bit?
Janus Troelsen
Panggilan bagus, ya itu akan ... Saya diberitahu bahwa saya perlu menggunakan malloc, pernahkah itu?
TechplexEngineer
ya tentu saja. super mudah:char* buffer = (char*) malloc(sizeof(char) * 50);
Janus Troelsen
@JanusTroelsen, atau jauh lebih bersih, lebih kecil, dapat dipelihara:char *buffer = malloc(sizeof(*buffer) * 50);
Shahbaz
Mengapa "% B" berbeda dari "% b" dalam hal ini? Jawaban sebelumnya mengatakan hal-hal seperti "Tidak ada fungsi format di pustaka standar C untuk menghasilkan biner seperti itu." dan " Beberapa runtime mendukung"% b "walaupun itu bukan standar." .
Peter Mortensen
8

Beberapa runtime mendukung "% b" walaupun itu bukan standar.

Lihat juga di sini untuk diskusi yang menarik:

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

HTH

rlerallut
sumber
1
Ini sebenarnya adalah properti dari perpustakaan runtime C, bukan kompiler.
cjm
7

Kode ini harus menangani kebutuhan Anda hingga 64 bit. Saya membuat 2 fungsi pBin & pBinFill. Keduanya melakukan hal yang sama, tetapi pBinFill mengisi ruang terkemuka dengan fillChar. Fungsi uji menghasilkan beberapa data uji, lalu mencetaknya menggunakan fungsi tersebut.



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
mrwes
sumber
1
"#define width 64" konflik dengan stream.h dari log4cxx. Tolong, gunakan nama yang didefinisikan secara acak konvensional :)
kagali-san
5
@ mhambra: Anda harus memberi tahu log4cxx off karena menggunakan nama generik seperti itu width!
u0b34a0f6ae
7

Apakah ada konverter printf untuk mencetak dalam format biner?

The printf()keluarga hanya mampu mencetak dalam basis 8, 10, dan 16 dengan menggunakan penentu standar langsung. Saya sarankan membuat fungsi yang mengubah angka menjadi string per kebutuhan khusus kode.


Untuk mencetak basis apa pun [2-36]

Semua jawaban lain sejauh ini memiliki setidaknya satu dari keterbatasan ini.

  1. Gunakan memori statis untuk buffer kembali. Ini membatasi berapa kali fungsi dapat digunakan sebagai argumen printf().

  2. Alokasikan memori yang membutuhkan kode panggilan ke pointer gratis.

  3. Memerlukan kode panggilan untuk secara eksplisit menyediakan buffer yang sesuai.

  4. Hubungi printf()langsung. Ini mewajibkan fungsi baru untuk untuk fprintf(), sprintf(), vsprintf(), dll

  5. Gunakan rentang integer yang dikurangi.

Berikut ini tidak memiliki batasan di atas . Itu membutuhkan C99 atau lebih baru dan penggunaan "%s". Ini menggunakan senyawa literal untuk menyediakan ruang buffer. Tidak memiliki masalah dengan beberapa panggilan dalam a 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;
}

Keluaran

1020304 5060708
1000000100000001100000100 101000001100000011100001000
100401404
A2F44
chux - Pasang kembali Monica
sumber
Ini sangat berguna. Apakah Anda tahu cara menggunakannya di C ++? Ketika saya mengkompilasi, itu menghasilkan kesalahan "Severity Code Description Project File Line Suppression State Error C4576 tipe dipatenkan diikuti oleh daftar penginisialisasi adalah sintaks konversi tipe eksplisit non-standar halo halo C: \ my_projects \ hello \ hello \ main.cpp 39 "
Baru belajar
1
@Justalearner Ini menghasilkan C ++ karena jika menggunakan senyawa fitur C literal yang bukan bagian dari C ++. Mungkin memposting implementasi C ++ Anda yang mencoba melakukan hal yang sama - bahkan jika tidak lengkap, saya yakin Anda akan mendapatkan bantuan - selama Anda menunjukkan upaya Anda terlebih dahulu.
chux - Reinstate Monica
6

Mungkin sedikit OT, tetapi jika Anda hanya membutuhkan ini untuk debug untuk memahami atau menelusuri kembali beberapa operasi biner yang Anda lakukan, Anda mungkin melihat wcalc (kalkulator konsol sederhana). Dengan opsi -b Anda mendapatkan output biner.

misalnya

$ wcalc -b "(256 | 3) & 0xff"
 = 0b11
quinmars
sumber
1
ada beberapa opsi lain di bagian depan ini, juga ... ruby -e 'printf("%b\n", 0xabc)', dcdiikuti oleh 2odiikuti oleh 0x123p, dan sebagainya.
lindes
6

Tidak ada fungsi format di pustaka standar C untuk menghasilkan biner seperti itu. Semua operasi format yang didukung keluarga printf adalah terhadap teks yang dapat dibaca manusia.

Florian Bösch
sumber
5

Fungsi rekursif berikut mungkin berguna:

void bin(int n)
{
    /* Step 1 */
    if (n > 1)
        bin(n/2);
    /* Step 2 */
    printf("%d", n % 2);
}
kapil
sumber
7
Hati-hati, ini tidak bekerja dengan bilangan bulat negatif.
Anderson Freitas
4

Saya mengoptimalkan solusi teratas untuk ukuran dan C ++ - ness, dan mendapatkan solusi ini:

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;
}
paniq
sumber
3
Jika Anda ingin menggunakan memori dinamis (melalui std::string), Anda mungkin juga menyingkirkan staticarray. Cara paling sederhana adalah dengan hanya menjatuhkan statickualifikasi dan menjadikan blokal ke fungsi.
Shahbaz
((x>>z) & 0x01) + '0'Cukup.
Jason C
4

Cetak bit dari jenis apa pun menggunakan lebih sedikit kode dan sumber daya

Pendekatan ini memiliki atribut:

  • Bekerja dengan variabel dan literal.
  • Tidak mengulangi semua bit saat tidak perlu.
  • Panggil printf hanya ketika menyelesaikan satu byte (tidak perlu untuk semua bit).
  • Bekerja untuk semua jenis.
  • Bekerja dengan endianness kecil dan besar (menggunakan GCC #defines untuk memeriksa).
  • Menggunakan typeof () yang bukan standar C tetapi sebagian besar didefinisikan.
#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;
}

Keluaran

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

Saya telah menggunakan pendekatan lain ( bitprint.h ) untuk mengisi tabel dengan semua byte (sebagai string bit) dan mencetaknya berdasarkan input / index byte. Layak untuk dilihat.

Geyslan G. Bem
sumber
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');
    }

}
малин чекуров
sumber
Atau tambahkan 0 atau 1 ke nilai karakter '0';) Tidak diperlukan terner.
Burung hantu
3

Saya menyukai kode oleh paniq, buffer statis adalah ide yang bagus. Namun gagal jika Anda ingin beberapa format biner dalam printf tunggal () karena selalu mengembalikan pointer yang sama dan menimpa array.

Ini adalah drop-in gaya C yang memutar pointer pada buffer split.

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;
}
eMPee584
sumber
1
Setelah countmencapai MAXCNT - 1, penambahan berikutnya countakan membuatnya MAXCNTbukan nol, yang akan menyebabkan akses keluar dari batas-batas array. Anda seharusnya melakukannya count = (count + 1) % MAXCNT.
Shahbaz
1
Ngomong-ngomong, ini akan mengejutkan bagi pengembang yang menggunakan MAXCNT + 1panggilan ke fungsi ini dalam satu printf. Secara umum, jika Anda ingin memberikan opsi untuk lebih dari 1 hal, buatlah tak terbatas. Angka seperti 4 hanya dapat menyebabkan masalah.
Shahbaz
3

Tidak ada cara standar dan portabel.

Beberapa implementasi menyediakan itoa () , tetapi tidak akan di sebagian besar, dan memiliki antarmuka yang agak payah. Tetapi kodenya ada di belakang tautan dan seharusnya membiarkan Anda menerapkan formatter Anda sendiri dengan mudah.

Wnoise
sumber
3

Satu pernyataan konversi generik dari semua tipe integral ke representasi string biner menggunakan pustaka standar :

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

Atau hanya: std::cout << std::bitset<sizeof(num) * 8>(num);

luart
sumber
1
Itu solusi idiomatis untuk C ++ tetapi dia meminta C.
danijar
3

Solusi saya:

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");
SarahGaidi
sumber
3

Berdasarkan saran @ ideasman42 di jawabannya, ini adalah makro yang menyediakan int8, 16, 32& 64versi, menggunakan kembali INT8makro untuk menghindari pengulangan.

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

Output ini:

My Flag 0001011011100001001010110111110101111000100100001111000000101000

Untuk keterbacaan, Anda dapat mengubah: #define PRINTF_BINARY_SEPARATORmenjadi#define PRINTF_BINARY_SEPARATOR "," atau#define PRINTF_BINARY_SEPARATOR " "

Ini akan menampilkan:

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

atau

My Flag 00010110 11100001 00101011 01111101 01111000 10010000 11110000 00101000
Et7f3XIV
sumber
terima kasih menyalin kode ini, yang pertama untuk menyalin dalam proyek ini saya kerjakan, menulis ini terasa seperti tugas yang membosankan :)
DevZer0
3

Menggunakan:

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

Untuk referensi lebih lanjut, lihat Cara mencetak nomor biner melalui printf .

kapilddit
sumber
1
Jawaban sebelumnya mengatakan "Beberapa implementasi menyediakan itoa (), tetapi sebagian besar tidak akan" ?
Peter Mortensen
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);
        }
}

harus bekerja - belum diuji.

olli
sumber
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" */
Ben Cordero
sumber
4
Membayar biaya malokasi akan merusak kinerja. Melewati tanggung jawab untuk penghancuran buffer ke pemanggil tidak baik.
EvilTeach
2

Berikutnya akan menunjukkan kepada Anda tata letak memori:

#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;
}
Yola
sumber
Apa yang Anda maksud dengan "Next akan menunjukkan kepada Anda tata letak memori" ?
Peter Mortensen
2

Berikut ini adalah variasi kecil dari solusi paniq yang menggunakan templat untuk memungkinkan pencetakan integer 32 dan 64 bit:

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

Dan bisa digunakan seperti:

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() );

Inilah hasilnya:

  0x1e127ad: 00000001111000010010011110101101
0x2e0b04ce0: 0000000000000000000000000000001011100000101100000100110011100000
Leo
sumber