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

我可以使用printf作为hex或八进制数进行打印。 有格式标签打印为二进制,或任意的基地?

我正在运行gcc。

printf("%d %x %o\n", 10, 10, 10); //prints "10 A 12\n" print("%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)); 

对于多字节types

 printf("m: "BYTE_TO_BINARY_PATTERN" "BYTE_TO_BINARY_PATTERN"\n", BYTE_TO_BINARY(m>>8), BYTE_TO_BINARY(m)); 

你不幸的是需要所有额外的引号。 这种方法存在macros的效率风险(不要将函数作为parameter passing给BYTE_TO_BINARY ),而是避免内存问题和在这里的其他一些提议中多次调用strcat。

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

 //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(""); } 

testing

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

这里是一个简单的黑客演示技术来做你想做的事情。

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

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

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

这里是一个如何在glibc中实现自定义printf格式的例子 。

这是一个不受重入问题影响的函数的版本,或者限制参数的大小/types:

 #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之间的任何基数也是可以的,如果你只是用期望的基数replace2。 用法是:

 char tmp[FMT_BUF_SIZE]; printf("%s\n", binary_fmt(x, tmp)); 

其中x是任何整数expression式。

惊讶的是,没有人这样说,但你可以用一张小桌子来提高速度1 。 在embedded式领域中,类似的技术是非常有用的,例如反转一个字节:

 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我主要是指embedded式应用程序,其中优化器不那么积极,速度差异是可见的。

打印最低有效位并将其右移。 这样做直到整数变成零打印二进制表示没有前导零,但在相反的顺序。 使用recursion,顺序可以很容易地纠正。

 #include <stdio.h> void print_binary(int number) { if (number) { print_binary(number >> 1); putc((number & 1) ? '1' : '0', stdout); } } 

对我来说,这是解决这个问题最简单的方法之一。 如果你喜欢0b前缀和尾随的新行字符,我build议包装function。

在线演示

以上都不是我正在寻找的,所以我写了一个。 超级简单的在printf中使用%B!

  /* * 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]); //Begin 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 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); } 
 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; } 

基于@William Whyte的回答,这是一个提供INT864版本的macros,重用INT8macros以避免重复。

 /* --- 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 

有些运行时支持“%b”,尽pipe这不是一个标准。

另请参阅这里进行一个有趣的讨论:

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

HTH

这个代码应该处理你的需要高达64位。 我创build了2个函数pBin&pBinFill。 两者都做同样的事情,但pBinFill用fillChar填充前导空格。 testingfunction生成一些testing数据,然后使用该function打印出来。

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

C标准库没有格式化function输出二进制文件。 printf系列支持的所有格式操作都是针对人类可读的文本。

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

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

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

例如

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

下面的recursion函数可能是有用的

 void bin(int n) { /* step 1 */ if (n > 1) bin(n/2); /* step 2 */ printf("%d", n % 2); } 

printf()系列仅能够使用标准说明符直接在基本8,10和16中进行打印。 build议创build一个将数字转换为每个代码特定需求的string的函数。


迄今为止所有其他的答案至less有一个这样的限制。

  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) // .. compound literal .. #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 char *my_to_base(char *dest, unsigned i, int base) { assert(base >= 2 && base <= 36); char *s = &dest[TO_BASE_N - 1]; *s = '\0'; do { s--; *s = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"[i % base]; i /= base; } while (i); 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)); return 0; } 

产量

 1020304 5060708 1000000100000001100000100 101000001100000011100001000 100401404 

没有标准和便携的方式。

一些实现提供itoa() ,但它不会在大多数,它有一个有点不好的接口。 但代码是在链接后面,应该让你很容易地实现自己的格式化。

我的解决scheme

 long unsigned int i; for(i = 0u; i < sizeof(integer) * CHAR_BIT; i++) { if(integer & LONG_MIN) printf("1"); else printf("0"); integer <<= 1; } printf("\n"); 
 void print_ulong_bin(const unsigned long * const var, int bits) { int i; #if defined(__LP64__) || defined(_LP64) if( (bits > 64) || (bits <= 0) ) #else if( (bits > 32) || (bits <= 0) ) #endif return; for(i = 0; i < bits; i++) { printf("%lu", (*var >> (bits - 1 - i)) & 0x01); } } 

应该工作 – 未经testing。

 /* Convert an int to it's binary representation */ char *int2bin(int num, int pad) { char *str = malloc(sizeof(char) * (pad+1)); if (str) { str[pad]='\0'; while (--pad>=0) { str[pad] = num & 1 ? '1' : '0'; num >>= 1; } } else { return ""; } return str; } /* example usage */ printf("The number 5 in binary is %s", int2bin(5, 4)); /* "The number 5 in binary is 0101" */ 

我喜欢paniq的代码,静态缓冲区是个好主意。 但是,如果你想在一个printf()中使用多个二进制格式,它将会失败,因为它总是返回相同的指针并覆盖数组。

这里有一个C风格的插件,它在旋转的缓冲区上旋转指针。

 char * format_binary(unsigned int x) { #define MAXLEN 8 // width of output format #define MAXCNT 4 // count per printf statement static char fmtbuf[(MAXLEN+1)*MAXCNT]; static int count = 0; char *b; count = count % MAXCNT + 1; b = &fmtbuf[(MAXLEN+1)*count]; b[MAXLEN] = '\0'; for (int z = 0; z < MAXLEN; z++) { b[MAXLEN-1-z] = ((x>>z) & 0x1) ? '1' : '0'; } return b; } 

接下来会显示给你的内存布局:

 #include <limits> #include <iostream> #include <string> using namespace std; template<class T> string binary_text(T dec, string byte_separator = " ") { char* pch = (char*)&dec; string res; for (int i = 0; i < sizeof(T); i++) { for (int j = 1; j < 8; j++) { res.append(pch[i] & 1 ? "1" : "0"); pch[i] /= 2; } res.append(byte_separator); } return res; } int main() { cout << binary_text(5) << endl; cout << binary_text(.1) << endl; return 0; } 
 char buffer [33]; itoa (value,buffer,2); printf ("\nbinary: %s\n",buffer); 

为更多的参考。 如何通过printf打印二进制数字

 #include<stdio.h> #include<conio.h> void main() { clrscr(); printf("Welcome\n\n\n"); unsigned char x='A'; char ch_array[8]; for(int i=0;x!=0;i++) { ch_array[i] = x & 1; x = x >>1; } for(--i;i>=0;i--) printf("%d",ch_array[i]); getch(); } 

这里是paniq的解决scheme的一个小的变化,它使用模板来允许打印32位和64位整数:

 template<class T> inline std::string format_binary(T x) { char b[sizeof(T)*8+1] = {0}; for (size_t z = 0; z < sizeof(T)*8; z++) b[sizeof(T)*8-1-z] = ((x>>z) & 0x1) ? '1' : '0'; return std::string(b); } 

并可以使用像:

 unsigned int value32 = 0x1e127ad; printf( " 0x%x: %s\n", value32, format_binary(value32).c_str() ); unsigned long long value64 = 0x2e0b04ce0; printf( "0x%llx: %s\n", value64, format_binary(value64).c_str() ); 

结果如下:

  0x1e127ad: 00000001111000010010011110101101 0x2e0b04ce0: 0000000000000000000000000000001011100000101100000100110011100000 

我只想发布我的解决scheme。 它被用来得到一个字节的零和一个字节,但几次调用这个函数可以用于更大的数据块。 我用它的128位或更大的结构。 您也可以修改它以使用size_t作为input参数和指向要打印的数据的指针,因此它可以独立于大小。 但它对我的作品戒烟很好。

 void print_binary(unsigned char c) { unsigned char i1 = (1 << (sizeof(c)*8-1)); for(; i1; i1 >>= 1) printf("%d",(c&i1)!=0); } void get_binary(unsigned char c, unsigned char bin[]) { unsigned char i1 = (1 << (sizeof(c)*8-1)), i2=0; for(; i1; i1>>=1, i2++) bin[i2] = ((c&i1)!=0); } 

下面是我如何做一个unsigned int

 void printb(unsigned int v) { unsigned int i, s = 1<<((sizeof(v)<<3)-1); // s = only most significant bit at 1 for (i = s; i; i>>=1) printf("%d", v & i || 0 ); } 

C中的一个小实用函数在解决位操作问题的时候做到这一点。 这通过使用掩码(1 <)检查每个设置位的string

 void printStringAsBinary(char * input) { char * temp = input; int i = 7, j =0;; int inputLen = strlen(input); /* Go over the string, check first bit..bit by bit and print 1 or 0 **/ for (j = 0; j < inputLen; j++) { printf("\n"); while (i>=0) { if (*temp & (1 << i)) { printf("1"); } else { printf("0"); } i--; } temp = temp+1; i = 7; printf("\n"); } } 

另一种以二进制打印的方法是: 首先转换整数

要以二进制打印6 ,请将6更改为110 ,然后打印"110"

旁观char buf[]问题。
printf()格式说明符,标志和像"%08lu""%*lX"这样的字段仍然可用。
不仅二进制(基2),这种方法可扩展到其他基地高达16。
限于较小的整数值。

 #include <stdint.h> #include <stdio.h> #include <inttypes.h> unsigned long char_to_bin10(char ch) { unsigned char uch = ch; unsigned long sum = 0; unsigned long power = 1; while (uch) { if (uch & 1) { sum += power; } power *= 10; uch /= 2; } return sum; } uint64_t uint16_to_bin16(uint16_t u) { uint64_t sum = 0; uint64_t power = 1; while (u) { if (u & 1) { sum += power; } power *= 16; u /= 2; } return sum; } void test(void) { printf("%lu\n", char_to_bin10(0xF1)); // 11110001 printf("%" PRIX64 "\n", uint16_to_bin16(0xF731)); // 1111011100110001 }