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

我正在运行gcc。

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

当前回答

我的解决方案返回一个int,然后可以在printf中使用。它还可以以大端序或小端序返回位。

#include <stdio.h>
#include <stdint.h>

int binary(uint8_t i,int bigEndian)
{
    int j=0,m = bigEndian ? 1 : 10000000;
    while (i)
    {
        j+=m*(i%2);
        if (bigEndian) m*=10; else m/=10;
        i >>= 1;
    }
    return j;
}

int main()
{
    char buf[]="ABCDEF";
    printf("\nbig endian = ");
    for (int i=0; i<5; i++) printf("%08d ",binary(buf[i],1));
    printf("\nwee endian = ");
    for (int i=0; i<5; i++) printf("%08d ",binary(buf[i],0));
    getchar();
    return 0;
}

输出

big endian = 01000001 01000010 01000011 01000100 01000101 01000110
wee endian = 10000010 01000010 11000010 00100010 10100010 01100010

其他回答

c

// Based on https://stackoverflow.com/a/112956/1438550

#include <stdio.h>
#include <stdint.h>

const char *int_to_binary_str(int x, int N_bits){
    static char b[512];
    char *p = b;
    b[0] = '\0';

    for(int i=(N_bits-1); i>=0; i--){
      *p++ = (x & (1<<i)) ? '1' : '0';
      if(!(i%4)) *p++ = ' ';
    }
    return b;
}

int main() {
  for(int i=31; i>=0; i--){
    printf("0x%08X %s \n", (1<<i), int_to_binary_str((1<<i), 32));
  }
  return 0;
}

期望的行为:

Run:
gcc -pthread -Wformat=0 -lm -o main main.c; ./main

Output:
0x80000000 1000 0000 0000 0000 0000 0000 0000 0000  
0x40000000 0100 0000 0000 0000 0000 0000 0000 0000  
0x20000000 0010 0000 0000 0000 0000 0000 0000 0000  
0x10000000 0001 0000 0000 0000 0000 0000 0000 0000  
0x08000000 0000 1000 0000 0000 0000 0000 0000 0000  
0x04000000 0000 0100 0000 0000 0000 0000 0000 0000  
0x02000000 0000 0010 0000 0000 0000 0000 0000 0000  
0x01000000 0000 0001 0000 0000 0000 0000 0000 0000  
0x00800000 0000 0000 1000 0000 0000 0000 0000 0000  
0x00400000 0000 0000 0100 0000 0000 0000 0000 0000  
0x00200000 0000 0000 0010 0000 0000 0000 0000 0000  
0x00100000 0000 0000 0001 0000 0000 0000 0000 0000  
0x00080000 0000 0000 0000 1000 0000 0000 0000 0000  
0x00040000 0000 0000 0000 0100 0000 0000 0000 0000  
0x00020000 0000 0000 0000 0010 0000 0000 0000 0000  
0x00010000 0000 0000 0000 0001 0000 0000 0000 0000  
0x00008000 0000 0000 0000 0000 1000 0000 0000 0000  
0x00004000 0000 0000 0000 0000 0100 0000 0000 0000  
0x00002000 0000 0000 0000 0000 0010 0000 0000 0000  
0x00001000 0000 0000 0000 0000 0001 0000 0000 0000  
0x00000800 0000 0000 0000 0000 0000 1000 0000 0000  
0x00000400 0000 0000 0000 0000 0000 0100 0000 0000  
0x00000200 0000 0000 0000 0000 0000 0010 0000 0000  
0x00000100 0000 0000 0000 0000 0000 0001 0000 0000  
0x00000080 0000 0000 0000 0000 0000 0000 1000 0000  
0x00000040 0000 0000 0000 0000 0000 0000 0100 0000  
0x00000020 0000 0000 0000 0000 0000 0000 0010 0000  
0x00000010 0000 0000 0000 0000 0000 0000 0001 0000  
0x00000008 0000 0000 0000 0000 0000 0000 0000 1000  
0x00000004 0000 0000 0000 0000 0000 0000 0000 0100  
0x00000002 0000 0000 0000 0000 0000 0000 0000 0010  
0x00000001 0000 0000 0000 0000 0000 0000 0000 0001 

但对我来说很管用:

#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。

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

没有标准的printf格式说明符来完成“二进制”输出。这是我在需要的时候设计的替代方案。

我的适用范围从2到36。它将数字扇出到递归调用的调用帧中,直到它到达一个比基数小的数字。然后它向后“遍历”,向前填充缓冲区,然后返回。返回值是使用的大小,如果缓冲区不够大,则返回-1。

int conv_rad (int num, int rad, char *s, int n) {
    char *vec = "0123456789" "ABCDEFGHIJKLM" "NOPQRSTUVWXYZ";
    int off;
    if (n == 0) return 0;
    if (num < rad) { *s = vec[num]; return 1; }
    off = conv_rad(num/rad, rad, s, n);
    if ((off == n) || (off == -1)) return -1;
    s[off] = vec[num%rad];
    return off+1;
}

一个重要的警告:这个函数是为“Pascal”风格的字符串设计的,它可以携带自己的长度。因此,如前所述,conv_rad不会以空终止缓冲区。对于更一般的C用法,它可能需要一个简单的包装器来执行空终止。或者对于打印,只需将赋值更改为putchar()。

void binario(int num) {
  for(int i=0;i<32;i++){
    (num&(1<i))? printf("1"):
        printf("0");
  }  
  printf("\n");
}

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

printf()家族只能直接使用标准说明符打印以8、10和16为基数的整数。我建议创建一个函数,根据代码的特定需要将数字转换为字符串。

[Edit 2022]这预计将在C的下一个版本中改变,实现“%b”。

二进制常量,如0b10101010和printf()函数族C2x的%b转换说明符


以任何基色打印[2-36]

到目前为止,所有其他答案都至少有一个这样的局限。

使用静态内存作为返回缓冲区。这限制了函数可以作为printf()的参数使用的次数。 将需要调用代码的内存分配给释放指针。 要求调用代码显式地提供一个合适的缓冲区。 直接调用printf()。这迫使一个新函数用于fprintf(), sprintf(), vsprintf()等。 使用缩小的整数范围。

以下内容没有上述限制。它确实需要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[TO_BASE_N], 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
  // size_t len = &buf[TO_BASE_N] - s;
  // memmove(buf, s, len);

  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