c - बाइनरी प्रारूप में प्रिंट करने के लिए कोई printf कनवर्टर है?




(20)

Print bits from any type using less code and resources

This approach has as attributes:

  • Works with variables and literals.
  • Doesn't iterate all bits when not necessary.
  • Call printf only when complete a byte (not unnecessarily for all bits).
  • Works for any type.
  • Works with little and big endianness (uses GCC #defines for checking).
  • Uses typeof() that isn't C standard but is largely defined.
#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 

I have used another approach ( bitprint.h ) to fill a table with all bytes (as bit strings) and print them based on the input/index byte. It's worth taking a look.

मैं printf के साथ एक हेक्स या ऑक्टल संख्या के रूप में प्रिंट कर सकते हैं। बाइनरी, या मनमाने ढंग से आधार के रूप में मुद्रित करने के लिए एक प्रारूप टैग है?

मैं जीसीसी चला रहा हूँ।

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

अगला आपको मेमोरी लेआउट दिखाएगा:

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

आप गति 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 मैं ज्यादातर एम्बेडेड अनुप्रयोगों का जिक्र कर रहा हूं जहां अनुकूलक इतने आक्रामक नहीं हैं और गति अंतर दिखाई दे रहा है।


आप जो चाहते हैं उसे करने के लिए तकनीकों का प्रदर्शन करने के लिए यहां एक त्वरित हैक है।

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

इस तरह बाइनरी आउटपुट करने के लिए सी मानक लाइब्रेरी में कोई स्वरूपण कार्य नहीं है। प्रिंटफ परिवार का समर्थन करने वाले सभी प्रारूप संचालन मानव पठनीय पाठ की ओर हैं।


कम से कम महत्वपूर्ण बिट प्रिंट करें और इसे दाईं ओर बाहर स्थानांतरित करें। इसे पूर्ण करने तक शून्य पूर्ण होने के बावजूद बाइनरी प्रस्तुति शून्य हो जाती है लेकिन उलट क्रम में। रिकर्सन का उपयोग करके, ऑर्डर को आसानी से ठीक किया जा सकता है।

#include <stdio.h>

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

मेरे लिए, यह समस्या के सबसे साफ समाधानों में से एक है। यदि आपको 0 0b उपसर्ग और पिछला नया लाइन वर्ण पसंद है, तो मैं फ़ंक्शन को लपेटने का सुझाव देता हूं।

ऑनलाइन डेमो


कोई मानक और पोर्टेबल तरीका नहीं।

कुछ कार्यान्वयन itoa() प्रदान करते हैं, लेकिन यह अधिकतर नहीं होने वाला है, और इसमें कुछ हद तक क्रमी इंटरफ़ेस है। लेकिन कोड लिंक के पीछे है और आपको अपने स्वयं के फॉर्मेटर को आसानी से कार्यान्वित करने देना चाहिए।


निम्नलिखित रिकर्सिव फ़ंक्शन उपयोगी हो सकता है:

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

मुझे पनीक द्वारा कोड पसंद आया, स्थिर बफर एक अच्छा विचार है। हालांकि यह विफल रहता है यदि आप एक ही printf () में एकाधिक बाइनरी प्रारूप चाहते हैं क्योंकि यह हमेशा एक ही सूचक देता है और सरणी को ओवरराइट करता है।

यहां एक सी स्टाइल ड्रॉप-इन है जो एक स्प्लिट बफर पर पॉइंटर को घुमाता है।

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

मेरा समाधान:

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

मैंने आकार और सी ++ - नेस के लिए शीर्ष समाधान को अनुकूलित किया, और इस समाधान को प्राप्त किया:

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

यहां पनीक के समाधान की एक छोटी भिन्नता है जो 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

यहां बताया गया है कि मैंने इसे बिना हस्ताक्षरित 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 );
}

सामान्य रूप से glibc में एक बाइनरी रूपांतरण निर्दिष्ट नहीं है।

Glibc में कार्यों के printf () परिवार में कस्टम रूपांतरण प्रकार जोड़ना संभव है। विवरण के लिए register_printf_function देखें। यदि आप इसे उपलब्ध कराने के लिए एप्लिकेशन कोड को सरल बनाते हैं, तो आप अपने स्वयं के उपयोग के लिए एक कस्टम% बी रूपांतरण जोड़ सकते हैं।

ग्लिब में कस्टम प्रिंटफ प्रारूपों को कार्यान्वित करने का एक example यहां दिया गया है।


हो सकता है कि थोड़ा सा ओटी, लेकिन अगर आपको केवल कुछ बाइनरी ऑपरेशंस को समझने या उन्हें रिट्रेस करने के लिए डीबगिंग के लिए इसकी आवश्यकता है, तो आप wcalc (एक साधारण कंसोल कैलकुलेटर) पर एक नज़र डालेंगे। -b विकल्पों के साथ आपको बाइनरी आउटपुट मिलता है।

जैसे

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

INT8 व्हाइट के उत्तर के आधार पर, यह एक मैक्रो है जो पुनरावृत्ति से बचने के लिए INT8 मैक्रो का उपयोग करके INT8 , 16 , 32 और 64 संस्करण प्रदान करता है।

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

किसी भी डेटाटाइप के लिए बाइनरी प्रिंट करें

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

A small utility function in C to do this while solving a bit manipulation problem. This goes over the string checking each set bit using a mask (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");
    }
}

/* 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" */

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




printf