我可以使用printf
将数字以十六进制或八进制形式打印出来。是否有格式标签可以打印成二进制或其他任意进制?
我正在运行gcc。
printf("%d %x %o\n", 10, 10, 10); //prints "10 A 12\n"
printf("%b\n", 10); // prints "%b\n"
虽然不太规范,但对我来说很有效:
#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
中多次调用,而具有静态缓冲区的则不能。 - Patrick Schlüter打印任何数据类型的二进制
// 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;
}
size_t i; for (i=size; i-- > 0; )
,避免 size_t
和 int
不匹配的问题。 - chux - Reinstate Monicaptr
中的每个字节(外循环); 然后对当前字节中的每个位(内循环), 通过当前位掩码字节(1 << j
),将字节进行掩码处理。然后右移,得到一个包含0(0000 0000b
)或1 (0000 0001b
)的字节。使用格式为 %u
的printf打印结果字节。希望有所帮助。 - nielsbot>
和 >=
的边缘情况。在无符号类型中,0
是一个边缘情况,而且经常出现,这与带符号数学不同,后者使用不太常见的 INT_MAX/INT_MIN
。 - chux - Reinstate Monica这里有一个快速技巧,可以演示如何实现您想要的功能。
#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;
}
strcat
方法在每次循环添加单个字符到字符串上的效率较低。 相反,应该添加一个char *p = b;
,并用*p++ = (x & z) ? '1' : '0'
替换内部循环。 z
应该从128(2^7)开始,而不是256(2^8)。 考虑更新以接受指向缓冲区的指针(以实现线程安全),类似于inet_ntoa()
。 - tomlogicstrcat()
的参数使用了!我同意 strcat
可能比对解引用指针后进行后缀递增更容易理解,但即使是初学者也需要知道如何正确地使用标准库。也许使用索引数组进行赋值会是一个不错的示范(而且实际上可以工作,因为每次调用函数时 b
不会被重置为全零)。 - tomlogicprintf("%s + %s = %s", byte_to_binary(3), byte_to_binary(4), byte_to_binary(3+4))
。 - Paŭlo Ebermann在glibc中通常没有二进制转换说明符。
可以向glibc的printf()函数族中添加自定义转换类型。有关详细信息,请参见 register_printf_function。如果您发现自定义 %b 转换可简化应用程序代码并使其更易于使用,那么您可以添加它供自己使用。
以下是在glibc中实现自定义printf格式的 示例。
register_printf_specifier()
。新使用方法的示例可以在此处找到:https://codereview.stackexchange.com/q/219994/200418。 - alx - recommends codidact您可以使用一个小表格来提高速度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 我主要是指嵌入式应用程序,其中优化器不太激进,速度差异是可见的。
%s
以及相同数量的bit_rep[word >> 4K & 0xF..F]
参数应该就可以了。虽然我认为对于一个64位数字来说,输出16个字符串可能不会比循环64次并输出0/1更快。 - Shahbaz打印最低位并将其从右侧移出。重复此操作直到整数变为零,将以反向顺序打印二进制表示,但不带前导零。使用递归,可以很容易地纠正顺序。
#include <stdio.h>
void print_binary(unsigned int number)
{
if (number >> 1) {
print_binary(number >> 1);
}
putc((number & 1) ? '1' : '0', stdout);
}
对我来说,这是解决问题最干净的方法之一。如果你喜欢使用0b
前缀和一个换行符,请建议包装该函数。
putc('0'+(number&1), stdout);
- Roger Dueckint
值。 - isrnick截至2022年2月3日,GNU C库已更新至2.35版本。因此,%b
现在支持以二进制格式输出。
printf系列函数现在支持使用%b格式以二进制形式输出整数,该格式已在ISO C2X草案中规定,并且还推荐使用该格式的%B变体。
ldd --version
报告:ldd (Ubuntu GLIBC 2.35-0ubuntu3.1) 2.35
!问题在于**man 3 printf
对%b
和%B
完全保持沉默** :( - user5395338基于 @William Whyte 的回答,这是一个宏,提供了int8
,16
,32
和64
版本,重用 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;
}
这将输出:
My Flag 0001011011100001001010110111110101111000100100001111000000101000
为了易读性,您可能想添加一个分隔符,例如:
My Flag 00010110,11100001,00101011,01111101,01111000,10010000,11110000,00101000
PRINTF_BYTE_TO_BINARY_INT#
宏定义,以供选择使用。 - ideasman42以下是一个函数的版本,它不会出现可重入性问题或参数大小/类型的限制:
#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
是任何整数表达式时。
char *a = binary_fmt(x), *b = binary_fmt(y);
这样的语句将无法按预期工作。强制调用者传递缓冲区会使存储要求显式化; 当然,如果确实需要,调用者可以自由地使用静态缓冲区,那么重用同一缓冲区就变得显式化了。此外,请注意,在现代 PIC ABIs 上,与栈上的缓冲区相比,静态缓冲区通常需要更多的代码来访问。 - R.. GitHub STOP HELPING ICE快速简单的解决方案:
void printbits(my_integer_type x)
{
for(int i=sizeof(x)<<3; i; i--)
putchar('0'+((x>>(i-1))&1));
}
任何类型大小都适用,包括有符号和无符号整数。"&1" 是必需的,以处理有符号整数,因为移位可能会进行符号扩展。#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);
*int_to_bitstring_
方法都没有正确计算结果,或者是我漏掉了什么?printbits
运行正常。此外,对于大于32的十进制数,静态和分配方法的结果开始有所不同。我在C语言和位运算方面缺乏经验。 - edvard_munch
1010
,对吗? - Ciro Santilli OurBigBook.com