是否有printf转换器以二进制格式打印?

Bri*_*ian 404 c printf

我可以用printf作为十六进制或八进制数打印.是否有格式标记打印为二进制或任意基数?

我正在运行gcc.

printf("%d %x %o\n", 10, 10, 10); //prints "10 A 12\n"
print("%b\n", 10); // prints "%b\n"
Run Code Online (Sandbox Code Playgroud)

Wil*_*yte 248

Hacky但对我有用:

#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') 
Run Code Online (Sandbox Code Playgroud)
printf("Leading text "BYTE_TO_BINARY_PATTERN, BYTE_TO_BINARY(byte));
Run Code Online (Sandbox Code Playgroud)

对于多字节类型

printf("m: "BYTE_TO_BINARY_PATTERN" "BYTE_TO_BINARY_PATTERN"\n",
  BYTE_TO_BINARY(m>>8), BYTE_TO_BINARY(m));
Run Code Online (Sandbox Code Playgroud)

不幸的是,你需要所有额外的报价.这种方法具有宏的效率风险(不要将函数作为参数传递BYTE_TO_BINARY),但在此处的一些其他提议中避免了内存问题和strcat的多次调用.

  • 并且还有一个优点是可以在`printf`中多次调用,而`static`缓冲区则不能. (13认同)
  • 我冒昧地将`%d`改为`%c`,因为它应该更快('%d`必须执行数字 - >字符转换,而'%c`只是输出参数 (4认同)
  • 发布了这个宏的扩展版本,支持16,32,64位int:http://stackoverflow.com/a/25108449/432509 (3认同)
  • 请注意,此方法不适合堆栈.假设`int`在系统上是32位,打印单个32位值将需要32*4字节值的空间; 总共128个字节.根据堆栈大小,这可能是也可能不是问题. (2认同)
  • 在宏中的字节周围添加括号很重要,否则在发送操作 BYTE_TO_BINARY(a | b) -> a | 时可能会遇到问题。b & 0x01 != (a | b) & 0x01 (2认同)

小智 197

打印任何数据类型的二进制文件

//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("");
}
Run Code Online (Sandbox Code Playgroud)

测试

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;
}
Run Code Online (Sandbox Code Playgroud)

  • 建议`size_t i; for(i = size; i--> 0;)`以避免`size_t`与`int`不匹配. (8认同)
  • @ ZX9对你来说仍然是一个有用的原始注释,因为编码器确实需要小心,考虑边缘情况下使用`>`和`> =`和无符号类型."0"是无符号边缘情况,通常发生,与带有不太常见的"INT_MAX/INT_MIN"的带符号数学不同. (3认同)
  • 取'ptr`中的每个字节(外循环); 然后对于每个位当前字节(内部循环),用当前位("1 << j`)掩码字节.向右移动产生一个包含0('0000 0000b`)或1('0000 0001b`)的字节.以格式为'%u`打印生成的字节printf.HTH. (2认同)
  • @ZX9注意[建议的代码](http://stackoverflow.com/questions/111928/is-there-a-printf-converter-to-print-in-binary-format/3974138?noredirect=1#comment29671506_3974138)将“&gt;”与“size_t”一起使用,而不是注释中的“&gt;=”来确定何时终止循环。 (2认同)
  • 变量“byte”不应该是“bit”吗?而“b”实际上是字节数组。 (2认同)
  • 这可能是我一生中见过的最好的代码片段。看到地址被传递给由 void 指针指向的函数,同时传递数据类型大小,这对我来说本身就是一次大学讲座,也是一次纯粹的启蒙时刻。 (2认同)

Evi*_*ach 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;
}
Run Code Online (Sandbox Code Playgroud)

  • 一些变化:`strcat`是一种在循环的每次传递中向字符串添加单个char的低效方法.相反,添加一个`char*p = b;`并用`*p ++ =(x&z)替换内循环?'1':'0'.`z`应该从128(2 ^ 7)而不是256(2 ^ 8)开始.考虑更新以获取指向要使用的缓冲区的指针(用于线程安全),类似于`inet_ntoa()`. (43认同)
  • 此外,这应该记录在再次调用函数之前先前的结果将无效,因此调用者不应该尝试使用它:`printf("%s +%s =%s",byte_to_binary(3),byte_to_binary( 4),byte_to_binary(3 + 4))`. (8认同)
  • @EvilTeach:你自己使用三元运算符作为`strcat()`的参数!我同意`strcat`可能比后递增一个用于赋值的解引用指针更容易理解,但即使是初学者也需要知道如何正确使用标准库.使用索引数组进行赋值可能是一个很好的演示(并且实际上可以工作,因为每次调用函数时,`b`都不会重置为全零). (3认同)
  • 随机:二进制缓冲区char是静态的,并在分配中清除为全零.这只会在它第一次运行时清除它,之后它不会清除,而是使用最后一个值. (3认同)
  • 这肯定不如自定义为printf编写转义重载那么"怪异".对于不熟悉代码的开发人员来说,这很容易理解. (2认同)
  • 缺点是由于静态变量,这不是线程安全的。 (2认同)

DGe*_*try 82

通常,glibc中没有二进制转换说明符.

可以将自定义转换类型添加到glibc中的printf()函数系列中.有关详细信息,请参阅register_printf_function.您可以添加自定义%b转换以供自己使用,如果它简化了应用程序代码以使其可用.

以下是如何在glibc中实现自定义printf格式的示例.

  • `警告:'register_printf_function' 已被弃用 [-Wdeprecated-declarations]` 不过有一个新函数可以做同样的事情:`register_printf_specifier()`。可以在此处找到新用法的示例:https://codereview.stackexchange.com/q/219994/200418 (6认同)

Kal*_*fer 47

截至 2022 年 2 月 3 日,GNU C 库已更新至版本 2.35。因此,%b现在支持以二进制格式输出。

printf 系列函数现在支持二进制整数输出的 %b 格式(如 ISO C2X 草案中指定)以及 ISO C2X 草案推荐的该格式的 %B 变体。


Sha*_*baz 42

您可以使用小桌子来提高速度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]);
}
Run Code Online (Sandbox Code Playgroud)

1我主要指的是优化器不那么激进且速度差异可见的嵌入式应用程序.


dan*_*jar 21

打印最低位并将其移出右侧.执行此操作直到整数变为零将打印二进制表示而不会引导零,但按相反的顺序排列.使用递归,订单可以很容易地纠正.

#include <stdio.h>

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

对我而言,这是解决问题的最简洁的解决方案之一.如果你喜欢0b前缀和尾随的新行字符,我建议包装该函数.

在线演示

  • 您还应该使用unsigned int数字,因为当给定数字为负数时,该函数将输入永无休止的递归调用。 (2认同)
  • 更有效的方法,因为在 ASCII 中,'0'+1='1': `putc('0'+(number&amp;1), stdout);` (2认同)

ide*_*n42 19

基于@William怀特的回答,这是提供了一个宏int8,16,3264版本,再使用INT8宏来避免重复.

/* --- 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;
}
Run Code Online (Sandbox Code Playgroud)

这输出:

My Flag 0001011011100001001010110111110101111000100100001111000000101000
Run Code Online (Sandbox Code Playgroud)

为了便于阅读,您可能需要添加一个分隔符,例如:

My Flag 00010110,11100001,00101011,01111101,01111000,10010000,11110000,00101000
Run Code Online (Sandbox Code Playgroud)

  • 您如何建议添加逗号? (2认同)

R..*_*R.. 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;
}
Run Code Online (Sandbox Code Playgroud)

请注意,如果只是用所需的基数替换2,那么此代码对于2到10之间的任何基数都可以正常工作.用法是:

char tmp[FMT_BUF_SIZE];
printf("%s\n", binary_fmt(x, tmp));
Run Code Online (Sandbox Code Playgroud)

哪里x是积分表达式.

  • 这仍然是一个糟糕的设计.在这些情况下,它需要额外的复制步骤,并且即使在不需要复制的情况下,它也不会比调用者提供缓冲区贵**.使用静态存储只是一个不好的习惯. (7认同)
  • 是的,你可以这样做.但这是非常糟糕的设计.即使您没有线程或重入,调用者也必须知道静态缓冲区正在被重用,并且`char*a = binary_fmt(x),*b = binary_fmt(y);`之类的东西不会按预期工作.强制调用者传递缓冲区使存储需求明确; 如果确实需要,调用者当然可以自由地使用静态缓冲区,然后重用相同的缓冲区变得明确.另请注意,在现代PIC ABI上,静态缓冲区的访问代码通常比堆栈上的缓冲区要多. (6认同)
  • 在这里,我们不得不反对.我看不出如何添加一个不显眼的预处理器符号来限制使用情况严重,使得界面容易出错,保留永久存储的程序期间的临时值,并在最糟糕的生成代码的危害性附近的任何地方现代平台. (5认同)
  • 我没有提倡无理由的微优化(即测量).但我确实认为性能,即使是在微增益范围内,也值得一提,当它作为奖励以及基本优越的设计时. (5认同)
  • 必须使用必要的额外名称污染预处理程序或变量符号表的名称空间,必须使用该名称来正确调整_every_ caller必须分配的存储空间,并强制每个调用者知道此值并分配必要的数量存储,当简单的功能 - 本地存储解决方案足以满足大多数意图和目的时,以及当简单的strdup()调用覆盖其余99%的使用时,设计是不好的. (3认同)
  • 我建议使用堆栈存储.让调用者为此调用`malloc`会非常丑陋; 它不仅浪费大量时间和内存,而且最糟糕的是,你必须处理错误案例.我的意图始终是大多数调用者都会将指针传递给具有自动存储持续时间的数组.请注意,使用C99,它甚至可以是在调用时创建的复合文字. (3认同)
  • 在许多情况下,重入并不重要. (2认同)
  • 另外,你所说的wrt顺序处理多个结果本身并不是重入,而是简单地使用相当于全局对象来存储结果的余量.该函数不会被重新输入.在C中,用于处理将结果存储在全局对象中的函数的正确或至少广泛使用的习惯是在获得它们时立即复制这些结果.这具有的主要优点是,如果一次只需要一个结果,则不需要额外的分配. (2认同)

Rob*_*ugs 14

快速简便的解决方案:

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

适用于任何大小类型以及有符号和无符号整数。需要“&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)
Run Code Online (Sandbox Code Playgroud)

返回一个带有位的字符串稍后存储或打印怎么样?您可以分配内存并返回它,用户必须释放它,否则您返回一个静态字符串,但如果再次调用它或被另一个线程调用,它将被破坏。两种方法都显示:

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;
}
Run Code Online (Sandbox Code Playgroud)

致电:

// 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);
Run Code Online (Sandbox Code Playgroud)


小智 12

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;
}
Run Code Online (Sandbox Code Playgroud)

  • 如果在三元组中使用"1"和"0"而不是"49"和"48",则更清楚.此外,`b`应该是9个字符长,所以最后一个字符可以保持为空终止符. (6认同)
  • 如果你更改了一些内容:1.为最后的零增加空间:`static char b [9] = {0}`2.将声明移出循环:`int z,y;`3.添​​加最后的零: `b [y] = 0`.这样就不需要重新焕发活力了. (2认同)

Tec*_*eer 9

之前发布的答案都不是我想要的,所以我写了一个.使用%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);
    }
Run Code Online (Sandbox Code Playgroud)

  • 警告:这仅适用于glibc用户! (8认同)

rle*_*lut 8

一些运行时支持"%b",尽管这不是标准.

另见这里有趣的讨论:

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

HTH

  • 这实际上是 C 运行时库的属性,而不是编译器的属性。 (2认同)

mrw*_*wes 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;
}
Run Code Online (Sandbox Code Playgroud)

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;
}
Run Code Online (Sandbox Code Playgroud)

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
Run Code Online (Sandbox Code Playgroud)

  • @mhambra:你应该告诉log4cxx使用像`width`这样的通用名称! (4认同)

chu*_*ica 7

是否有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;
}
Run Code Online (Sandbox Code Playgroud)

产量

1020304 5060708
1000000100000001100000100 101000001100000011100001000
100401404
A2F44
Run Code Online (Sandbox Code Playgroud)

  • 这非常有用。你知道如何在C++中使用它吗?当我编译时,它会生成错误“严重性代码描述项目文件行抑制状态错误C4576括号类型后跟初始化程序列表是非标准显式类型转换语法hello C:\ my_projects \ hello \ hello \ main.cpp 39 ” (2认同)

Flo*_*sch 6

C标准库中没有格式化函数来输出这样的二进制文件.printf系列支持的所有格式操作都是针对人类可读的文本.


qui*_*ars 6

也许有点OT,但是如果你需要这个只是为了理解或回溯你正在做的一些二进制操作,你可以看看wcalc(一个简单的控制台计算器).使用-b选项可以获得二进制输出.

例如

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


pan*_*niq 5

我优化了大小和 C++-ness 的顶级解决方案,并得到了这个解决方案:

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;
}
Run Code Online (Sandbox Code Playgroud)

  • 如果你想使用动态内存(通过 `std::string`),你不妨去掉 `static` 数组。最简单的方法是去掉 `static` 限定符,并使 `b` 成为函数的局部变量。 (4认同)

kap*_*dit 5

使用:

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

有关更多参考,请参阅如何通过 printf 打印二进制数


kap*_*pil 5

以下递归函数可能很有用:

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

  • 注意,这不适用于负整数. (6认同)

Gey*_*Bem 5

使用更少的代码和资源打印任何类型的位

这种方法具有以下属性:

  • 适用于变量和文字。
  • 不必要时不会迭代所有位。
  • 仅当完成一个字节时才调用 printf(并非所有位都不需要)。
  • 适用于任何类型。
  • 适用于小端和大端(使用 GCC #defines 进行检查)。
  • 可以与 char 不是字节(八位)的硬件一起使用。(感谢@supercat)
  • 使用不是 C 标准但已广泛定义的 typeof()。
#include <stdio.h>
#include <stdint.h>
#include <string.h>
#include <limits.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));       \
})

#define MSB_MASK 1 << (CHAR_BIT - 1)

void __printb(void *value, size_t size)
{
        unsigned char uc;
        unsigned char bits[CHAR_BIT + 1];

        bits[CHAR_BIT] = '\0';
        for_endian(size) {
                uc = ((unsigned char *) value)[i];
                memset(bits, '0', CHAR_BIT);
                for (int j = 0; uc && j < CHAR_BIT; ++j) {
                        if (uc & MSB_MASK)
                                bits[j] = '1';
                        uc <<= 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);
        printb('A');
        printf("\n");

        return 0;
}
Run Code Online (Sandbox Code Playgroud)

输出

$ ./printb 
11111111 
11111111 
00000000 11111111 
00000000 00000000 00000000 11111111 
01000100 
00000000 00000000 00000000 01000100 
01000100 00010001 11111111 00000001 
00000000 01000011 
00000000 00000000 00000000 01000001 
Run Code Online (Sandbox Code Playgroud)

我使用了另一种方法(bitprint.h)用所有字节(作为位字符串)填充表并根据输入/索引字节打印它们。值得一看。


мал*_*ров 5

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

}
Run Code Online (Sandbox Code Playgroud)