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

我正在运行gcc。

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

当前回答

// m specifies how many of the low bits are shown.
// Replace m with sizeof(n) below for all bits and
// remove it from the parameter list if you like.

void print_binary(unsigned long n, unsigned long m) {
    static char show[3] = "01";
    unsigned long mask = 1ULL << (m-1);
    while(mask) {
        putchar(show[!!(n&mask)]); mask >>= 1;
    }
    putchar('\n');
}

其他回答

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

这种方法有以下属性:

使用变量和字面量。 没有必要时不迭代所有位。 只在完成一个字节时调用printf(不必对所有位都调用)。 适用于任何类型。 使用大小字节序(使用GCC #定义进行检查)。 可以与char不是字节(8位)的硬件一起工作。(谢谢大家@supercat) 使用typeof(),它不是C标准的,但在很大程度上是定义的。

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

输出

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

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

我优化了顶部的解决方案的大小和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;
}

下面的函数返回给定无符号整数的二进制表示形式,使用不带前导零的指针算术:

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

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

注意,不需要显式设置NUL结束符,因为buffer表示一个具有静态存储持续时间的对象,该对象已经被全0填充。

通过简单地修改num形式参数的类型,可以很容易地将其适应为无符号long long(或另一个无符号整数)。

CHAR_BIT要求包含<limits.h>。

下面是一个用法示例:

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

其期望输出为:

>>>                   1<<<
>>>11111110            <<<

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

还有一种想法是将数字转换为十六进制格式,然后将每个十六进制密码解码为四个“位”(1和0)。Sprintf可以为我们做位操作:

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

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