我可以用printf打印十六进制或八进制数字。是否有格式标签打印为二进制或任意基数?
我正在运行gcc。
printf("%d %x %o\n", 10, 10, 10); //prints "10 A 12\n"
printf("%b\n", 10); // prints "%b\n"
我可以用printf打印十六进制或八进制数字。是否有格式标签打印为二进制或任意基数?
我正在运行gcc。
printf("%d %x %o\n", 10, 10, 10); //prints "10 A 12\n"
printf("%b\n", 10); // prints "%b\n"
当前回答
glibc中通常没有二进制转换说明符。
在glibc中,可以向printf()函数家族添加自定义转换类型。有关详细信息,请参阅register_printf_function。如果可以简化应用程序代码,您可以添加自定义%b转换供自己使用。
下面是如何在glibc中实现自定义printf格式的示例。
其他回答
下面是一个不受重入性问题或参数大小/类型限制的函数版本:
#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到10之间的任何底数,只要将2替换为所需的底数。用法是:
char tmp[FMT_BUF_SIZE];
printf("%s\n", binary_fmt(x, tmp));
其中x是任意的积分表达式。
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');
}
}
打印最低有效位并向右移出。这样做直到整数变为零,打印的二进制表示没有前导零,但顺序相反。使用递归,可以很容易地纠正顺序。
#include <stdio.h>
void print_binary(unsigned int number)
{
if (number >> 1) {
print_binary(number >> 1);
}
putc((number & 1) ? '1' : '0', stdout);
}
对我来说,这是最干净的解决方案之一。如果您喜欢0b前缀和一个尾随的新行字符,我建议对函数进行包装。
在线演示
是否有一个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
快速简单的解决方法:
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);