バイナリ形式で印刷するprintfコンバーターはありますか?


434

16進数または8進数としてprintfを使用して印刷できます。バイナリまたは任意のベースとして印刷するフォーマットタグはありますか?

私はgccを実行しています。

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

私の知る限り、printfを使用してこれを行うことはできません。もちろん、これを実現するヘルパーメソッドを作成することもできますが、それは目的の方向とは思えません。
Ian P

そのために事前定義されたフォーマットはありません。自分で文字列に変換してから、文字列を出力する必要があります。
rslite 2008

簡単なGoogle検索で役立つ可能性のあるいくつかの情報を含むこのページが生成されました:forums.macrumors.com/archive/index.php/t-165959.html
Ian P

12
ANSI標準Cライブラリの一部ではありません-移植可能なコードを作成している場合、最も安全な方法は独自のコードをロールすることです。
tomlogic

C ++でのバイナリ文字列への変換の1つのステートメント標準および汎用(任意の長さの任意の整数型)ソリューション:stackoverflow.com/a/31660310/1814353
luart

回答:


266

ハッキーですが私のために働きます:

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

マルチバイトタイプの場合

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

残念ながら、すべての余分な引用符が必要です。このアプローチにはマクロの効率リスクがあります(関数をに引数として渡さないでくださいBYTE_TO_BINARY)が、ここで紹介する他のいくつかの提案では、メモリの問題とstrcatの複数の呼び出しを回避しています。


13
またprintfstaticバッファー付きのものではできない、複数回呼び出し可能なという利点もあります。
PatrickSchlüter、

4
私は自由にをに変更し%dまし%cた。これはさらに高速になるはずです(%d%c


2
このアプローチはスタックフレンドリーではないことに注意してください。intシステムで32ビットと想定すると、単一の32ビット値を印刷するには、32 * 4バイト値用のスペースが必要になります。合計128バイト。スタックサイズに応じて、問題になる場合と問題にならない場合があります。
user694733

1
マクロでバイトの前後に括弧を追加することが重要です。そうしないと、操作BYTE_TO_BINARY(a | b)-> a |を送信するときに問題が発生する可能性があります。b&0x01!=(a | b)&0x01
Ivan Hoffmann

203

任意のデータ型のバイナリを印刷する

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

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

テスト

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

8
提案size_t i; for (i=size; i-- > 0; )を避けるためにsize_tintミスマッチ。
chux-モニカを2013年

1
誰かがこのコードの背後にあるロジックについて詳しく説明してもらえますか?
jII 2014年

2
ptr(外部ループ)で各バイトを受け取ります。次に、現在のバイト(内部ループ)の各ビットについて、現在のビット(1 << j)でバイトをマスクします。その右にシフトすると、バイトは0(0000 0000b)または1(0000 0001b)になります。結果のバイトprintfをformatで出力します%u。HTH。
nielsbot 2016

1
ZX9お知らせ@ことを示唆したコードを使用>してsize_tではなく>=ループを終了したときにあなたのコメントのかを決定します。
chux-モニカを2016年

3
ZX9 @コーダーのエッジケースの使用を考慮に注意する必要がありそうであるようにあなたのまだ役に立つ元のコメント >>=符号なしのタイプでは。 0符号なしエッジケースであり、あまり一般的ではない符号付き数学とは異なり、通常発生しますINT_MAX/INT_MIN
chux-2016年

151

ここにあなたが望むことをするためのテクニックを示すための簡単なハックがあります。

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

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

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

    return b;
}

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

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

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

    {
        /* byte to binary string */

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

    return 0;
}

2
これは、printfのエスケープオーバーロードをカスタムで作成するよりも、「奇妙」ではありません。コードを初めて使用する開発者にとっても、理解するのは簡単です。
Furious Coder

43
いくつかの変更:strcatループの各パスで文字列に単一の文字を追加する非効率的な方法です。代わりに、a char *p = b;を追加し、内部ループをに置き換えます*p++ = (x & z) ? '1' : '0'z256(2 ^ 8)ではなく128(2 ^ 7)から開始する必要があります。と同様に、(スレッドセーフのために)使用するバッファへのポインタを取得するように更新することを検討してくださいinet_ntoa()
tomlogic

3
@EvilTeach:自分で三項演算子をパラメーターとして使用していますstrcat()!私strcatは、割り当ての逆参照されたポインタをポストインクリメントするよりもおそらく理解しやすいことに同意しますが、初心者でも標準ライブラリを適切に使用する方法を知る必要があります。おそらく、インデックス付き配列を割り当てに使用するのは良いデモでしょう(b関数を呼び出すたびにすべて0にリセットされないため、実際に機能します)。
tomlogic

3
ランダム:バイナリバッファcharは静的であり、割り当てではすべてゼロにクリアされます。これにより、最初に実行したときにのみクリアされ、その後はクリアされませんが、代わりに最後の値が使用されます。
markwatson、2010

8
また、これは、関数を再度呼び出した後は前の結果が無効になることを文書化する必要があるため、呼び出し元は次のように使用しないでくださいprintf("%s + %s = %s", byte_to_binary(3), byte_to_binary(4), byte_to_binary(3+4))
パウロEbermann

84

通常、glibcにはバイナリ変換指定子はありません。

glibcの関数のprintf()ファミリーにカスタム変換タイプを追加することが可能です。詳細については、register_printf_functionを参照してください。アプリケーションコードを簡略化して利用できるようにする場合は、独自に使用するためのカスタム%b変換を追加できます。

以下は、glibcでカスタムprintf形式を実装する方法のです。


私は常に、異なる基数が必要な限られたケースのために、独自のv [snf] printf()を作成してきました。
ジェイミー

3
warning: 'register_printf_function' is deprecated [-Wdeprecated-declarations]ただし、同じことを行う新しい関数がありますregister_printf_specifier()。新しい使用法の例は次の場所に
Cacahuete Frito

47

小さなテーブルを使用して速度を向上させることができます1。同様の手法は、たとえば、バイトを反転させるために、組み込みの世界で役立ちます。

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

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

1私は主に、オプティマイザがそれほど積極的ではなく、速度の違いが見える組み込みアプリケーションについて言及しています。


27

最下位ビットを出力し、右側にシフトアウトします。整数がゼロになるまでこれを行うと、先行ゼロなしで逆の順序でバイナリ表現が出力されます。再帰を使用すると、順序を簡単に修正できます。

#include <stdio.h>

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

私にとって、これは問題に対する最もクリーンな解決策の1つです。もし良かったら0b接頭辞と末尾の改行文字、関数をラップすることをお勧めします。

オンラインデモ


エラー:関数呼び出しには引数が少なすぎます。2が必要です。1putc((number&1)? '1': '0');
Koray Tugay

@KorayTugay指摘してくれてありがとう。関数呼び出しを修正し、デモを追加しました。
ダニジャー

6
また、unsigned int数値を使用する必要があります。これは、指定された数値が負の場合、関数が終了しない再帰呼び出しに入るからです。
パフィー

ASCIIでは '0' + 1 = '1'であるため、より効率的なアプローチ:putc('0'+(number&1), stdout);
Roger Dueck

22

@William Whyteの回答に基づくと、これは、、、およびバージョンを提供するマクロでint8あり16、繰り返しを避けるためにマクロを再利用します。3264INT8

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

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

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

これは出力します:

My Flag 0001011011100001001010110111110101111000100100001111000000101000

読みやすくするために、たとえば次のようなセパレータを追加できます。

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

これは素晴らしいです。最下位ビットで始まるビットを印刷する特別な理由はありますか?
gaganso 2017年

2
どのようにカンマを追加することをお勧めしますか?
nmz787 2017年

PRINTF_BYTE_TO_BINARY_INT#オプションで使用する定義のグループ化されたバージョンを追加します。
ideasman42

16

これは、再入可能性の問題や引数のサイズ/タイプの制限を受けないバージョンの関数です。

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

このコードは、2を目的のベースで置き換えるだけで、2から10までのベースでも同様に機能することに注意してください。使い方は:

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

x積分式はどこにありますか。


7
はい、できます。しかし、それは本当に悪いデザインです。スレッドや再入可能性がない場合でも、呼び出し元は静的バッファが再利用されていること、およびのようなものchar *a = binary_fmt(x), *b = binary_fmt(y);が期待どおりに機能しないことを認識する必要があります。呼び出し元に強制的にバッファを渡すと、ストレージ要件が明示されます。もちろん、呼び出し元は静的バッファーが本当に必要であれば自由に使用でき、同じバッファーの再利用が明示的になります。また、最新のPIC ABIでは、静的バッファーは通常、スタック上のバ​​ッファーよりもアクセスに多くのコードを必要とします。
R .. GitHub ICE HELPING ICEを停止する'26

8
それはまだ悪いデザインです。それらの場合には追加のコピー手順が必要であり、コピーが不要な場合でも呼び出し側がバッファーを提供するよりもコストがかかりません。静的ストレージを使用することは、悪いイディオムです。
R .. GitHub ICE HELPING ICEの停止2012年

3
すべての呼び出し元によって割り当てられる必要があるストレージのサイズを適切に設定し、すべての呼び出し元にこの値を知らせ、必要な量を割り当てるように強制する必要がある余分な名前でプリプロセッサまたは変数シンボルテーブルの名前空間を汚染する必要がある記憶域は、単純な関数ローカル記憶域ソリューションがほとんどの目的と目的に十分であり、単純なstrdup()呼び出しが残りの使用の99%をカバーする場合、設計が不適切です。
グレッグAウッズ

5
ここで私たちは同意する必要があります。控えめなプリプロセッサシンボルを1つ追加すると、使用例を厳しく制限し、インターフェイスにエラーが発生しやすくなり、プログラムの期間中、一時的な値のために永続的なストレージを確保し、ほとんどの場合より悪いコードを生成するという害の近くに、どうすればよいのかわかりません。最新のプラットフォーム。
R .. GitHub ICE HELPING ICEを停止

5
私は理由なしにマイクロ最適化(つまり、測定)を提唱していません。しかし、マイクロゲインスケールのパフォーマンスであっても、根本的に優れたデザインと合わせて、それがボーナスとなる場合は、言及する価値があると思います。
R .. GitHub ICE HELPING 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;
}

6
三項で'1'andの'0'代わりに49and を使用すると、より明確になり48ます。また、b最後の文字をヌルターミネーターのままにできるように、9文字の長さにする必要があります。
tomlogic

また、Bは毎回初期化する必要があります。
EvilTeach

2
一部を変更しない場合は、次のようにします。1.最後のゼロのスペースを追加しますstatic char b[9] = {0}。2.宣言をループの外に移動します。3 . int z,y;最後のゼロを追加しますb[y] = 0。この方法では、再初期化は必要ありません。
Kobor42 2012

1
素晴らしい解決策。でも私はいくつかのことを変えます。つまり、任意のサイズの入力を適切に処理できるように、文字列を逆方向に移動します。
Kobor42 2012

これら8のはすべてに置き換える必要がありますCHAR_BIT
2016年

12

迅速で簡単なソリューション:

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

あらゆるサイズのタイプと、符号付きおよび符号なしの整数で機能します。シフトは符号拡張を行う可能性があるため、「&1」は符号付き整数を処理するために必要です。

これを行うには非常に多くの方法があります。これは、符号付きまたは符号なし32ビットタイプから32ビットまたはnビットを印刷する(署名されている場合は負の値を入れず、実際のビットを印刷するだけ)キャリッジリターンなしの非常にシンプルなものです。ビットシフトの前にiが減分されることに注意してください。

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

後で保存または印刷するビットを含む文字列を返すのはどうですか?あなたはメモリを割り当ててそれを返すことができ、ユーザーがそれを解放する必要があるか、そうでなければ静的な文字列を返しますが、それが再び呼び出された場合、または別のスレッドによって呼び出された場合、それは破壊されます。示されている両方の方法:

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

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

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

次の電話番号:

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

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

10

以前に投稿された回答のどれもが私が探していたものとまったく同じではないため、1つ作成しました。%Bをprintf

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

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


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

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

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

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

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

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

        register_printf_specifier('B', printf_output_M, printf_arginfo_M);

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

        return (EXIT_SUCCESS);
    }

1
これは50ビット以上でオーバーフローしますか?
Janus Troelsen 2012年

よし、そうだね... mallocを使う必要があると言われたけど、絶対にやらない?
TechplexEngineer 2012年

はい、もちろん。超簡単:char* buffer = (char*) malloc(sizeof(char) * 50);
Janus Troelsen 2012年

@JanusTroelsen、またはよりクリーンで、小さく、保守可能:char *buffer = malloc(sizeof(*buffer) * 50);
Shahbaz

この点で、「%B」が「%b」と異なるのはなぜですか?以前の回答では、「C標準ライブラリには、そのようなバイナリを出力するためのフォーマット関数はありません」のようなものでした。一部のランタイムでは、標準ではありませんが、「%b」をサポートしています。」
Peter Mortensen 2017

8

一部のランタイムは「%b」をサポートしていますが、これは標準ではありません。

興味深い議論についてはこちらもご覧ください:

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

HTH


1
これは実際にはCランタイムライブラリのプロパティであり、コンパイラではありません。
cjm 2008

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 > 0);
 i++;   // point to last valid character
 sprintf(so,"%s",s+i); // stick it in the temp string string
 return so;
}

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

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

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

1
「#define width 64」は、log4cxxのstream.hと競合します。慣習的にランダムな定義名を使用してください:)
カガリさん、2011

5
@mhambra:そのような総称名をwidth代わりに使用する場合は、log4cxxをオフにする必要があります。
u0b34a0f6ae 2011年

7

バイナリ形式で印刷するprintfコンバーターはありますか?

printf()家族は、直接、標準的な指定子を使用してベース8、10、及び16で印刷することができます。コードの特定のニーズごとに数値を文字列に変換する関数を作成することをお勧めします。


任意のベースで印刷するには[2-36]

これまでの他のすべての回答には、これらの制限の少なくとも1つがあります。

  1. 戻りバッファに静的メモリを使用します。これにより、関数をの引数として使用できる回数が制限されますprintf()

  2. ポインタを解放するために呼び出しコードを必要とするメモリを割り当てます。

  3. 呼び出しコードが適切なバッファを明示的に提供することを要求します。

  4. printf()直接お電話ください。これfprintf()によりsprintf()、to 、、、などの新しい関数が必要になりますvsprintf()

  5. 整数の範囲を小さくしてください。

以下に上記の制限はありません。C99以降との使用が必要です"%s"。これは、使用する化合物リテラルをバッファ空間を提供します。での複数の呼び出しに問題はありませんprintf()

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

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

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

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

  return s;
}

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

出力

1020304 5060708
1000000100000001100000100 101000001100000011100001000
100401404
A2F44

これは非常に便利です。C ++での使用方法を知っていますか?コンパイルすると、次のエラーが発生します。 "
ただの学習者

1
@Justalearnerこれは、C ++の一部ではないC機能複合リテラルを使用するため、C ++を生成します。おそらく、同じことをしようとするC ++実装を投稿してください-たとえ不完全であっても、最初に試みを示しさえすれば、きっと助けが得られます。
chux-モニカを復活させる

6

少しOTかもしれませんが、これがデバッグのためだけに必要な場合は、実行しているいくつかのバイナリ演算を理解または追跡するために、wcalc(単純なコンソール計算機)を調べてみてください。-bオプションを使用すると、バイナリ出力が得られます。

例えば

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

1
この前面には他にもいくつかのオプションがあります... ruby -e 'printf("%b\n", 0xabc)'dc続いてが2o続き0x123pます。
lindes 2013年

6

C標準ライブラリには、そのようなバイナリを出力するためのフォーマット関数はありません。printfファミリーがサポートするすべてのフォーマット操作は、人間が読めるテキストを対象としています。


5

次の再帰関数が役立つ場合があります。

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

7
注意してください、これは負の整数では機能しません。
Anderson Freitas

4

私はサイズとC ++性のためにトップソリューションを最適化し、このソリューションにたどり着きました:

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

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

    return b;
}

3
(を介してstd::string)動的メモリを使用する場合は、static配列を削除することもできます。最も簡単な方法は、static修飾子を削除bして関数に対してローカルにすることです。
Shahbaz 2013

((x>>z) & 0x01) + '0'十分なものです。
Jason C

4

より少ないコードとリソースを使用して、あらゆるタイプのビットを出力します

このアプローチには属性があります:

  • 変数とリテラルで動作します。
  • 必要のないときにすべてのビットを反復しません。
  • 1バイトを完了するときにのみprintfを呼び出します(すべてのビットに対して不必要ではありません)。
  • すべてのタイプで機能します。
  • リトルエンディアンおよびビッグエンディアンで動作します(GCC #definesを使用してチェックします)。
  • C標準ではありませんが、主に定義されているtypeof()を使用します。
#include <stdio.h>
#include <stdint.h>
#include <string.h>

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

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

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

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

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

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

        return 0;
}

出力

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

別のアプローチ(bitprint.h)を使用して、すべてのバイトを(ビット文字列として)テーブルに入力し、入力/インデックスバイトに基づいてそれらを出力しました。一見の価値があります。


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

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

}

または、「0」の文字値に0または1を追加します;)3進数は必要ありません。
フクロウ

3

私はpaniqのコードが好きでした、静的バッファは良い考えです。ただし、単一のprintf()で複数のバイナリ形式が必要な場合は、常に同じポインタを返し、配列を上書きするため、失敗します。

これは、分割バッファでポインタを回転させるCスタイルのドロップインです。

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

1
count達するMAXCNT - 1と、次のの増分でゼロcountではMAXCNTなくそれが作成され、配列の境界外へのアクセスが発生します。あなたはやるべきだったcount = (count + 1) % MAXCNT
Shahbaz 2013

1
ちなみに、これは、後でMAXCNT + 1この関数の呼び出しを単一ので使用する開発者にとっては驚きprintfです。一般に、1つ以上のオプションを指定する場合は、それを無限にします。4などの数値は問題を引き起こすだけでした。
Shahbaz 2013

3

標準的でポータブルな方法はありません。

一部の実装はitoa()を提供していますが、ほとんどの実装には含まれず、やや不明瞭なインターフェースを持っています。しかし、コードはリンクの背後にあり、独自のフォーマッタをかなり簡単に実装できるはずです。


3

標準ライブラリを使用して、任意の整数型をバイナリ文字列表現に一般的に変換する1つのステートメント

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

あるいは単に: std::cout << std::bitset<sizeof(num) * 8>(num);


1
それはC ++の慣用的な解決策ですが、彼はCを求めていました
。– danijar

3

私の解決策:

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

3

@ ideasman42の回答での提案に基づくと、これは、、、およびバージョンを提供するマクロでint8あり16、繰り返しを避けるためにマクロを再利用します。3264INT8

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

このコードをコピーして
いただきありがとうござい


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

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

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

動作するはずです-テストされていません。


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

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

/* example usage */

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

4
不正配置のコストを支払うと、パフォーマンスが低下します。バッファの破壊に対する責任を呼び出し元に渡すことは不親切です。
EvilTeach

2

次に、メモリレイアウトが表示されます。

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

using namespace std;

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

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

    return 0;
}

「次はメモリレイアウトを表示します」とはどういう意味ですか?
Peter Mortensen 2017

2

以下は、テンプレートを使用して32ビットおよび64ビット整数の印刷を可能にするpaniqのソリューションの小さなバリエーションです。

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

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

    return std::string(b);
}

そして、次のように使用できます:

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

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

結果は次のとおりです。

  0x1e127ad: 00000001111000010010011110101101
0x2e0b04ce0: 0000000000000000000000000000001011100000101100000100110011100000
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.