我可以用printf作为十六进制或八进制数打印.是否有格式标记打印为二进制或任意基数?
我正在运行gcc.
printf("%d %x %o\n", 10, 10, 10); //prints "10 A 12\n" print("%b\n", 10); // prints "%b\n"
William Whyt.. 248
Hacky但对我有用:
#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的多次调用.
Hacky但对我有用:
#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的多次调用.
打印任何数据类型的二进制文件
//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; }
这是一个快速的黑客,以演示做你想要的技术.
#include/* printf */ #include /* strcat */ #include /* 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中没有二进制转换说明符.
可以将自定义转换类型添加到glibc中的printf()函数系列中.有关详细信息,请参阅register_printf_function.您可以添加自定义%b转换以供自己使用,如果它简化了应用程序代码以使其可用.
以下是如何在glibc中实现自定义printf格式的示例.
您可以使用小桌子来提高速度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我主要指的是优化器不那么激进且速度差异可见的嵌入式应用程序.
打印最低位并将其移出右侧.执行此操作直到整数变为零将打印二进制表示而不会引导零,但按相反的顺序排列.使用递归,订单可以很容易地纠正.
#includevoid print_binary(int number) { if (number) { print_binary(number >> 1); putc((number & 1) ? '1' : '0', stdout); } }
对我而言,这是解决问题的最简洁的解决方案之一.如果你喜欢0b
前缀和尾随的新行字符,我建议包装该函数.
在线演示
基于@William怀特的回答,这是提供了一个宏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 --- */ #includeint 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
这是一个不受重入问题影响的函数版本或对参数大小/类型的限制:
#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
是积分表达式.
const char* byte_to_binary( int x ) { static char b[sizeof(int)*8+1] = {0}; int y; long long z; for (z=1LL<0; z>>=1,y++) { b[y] = ( ((x & z) == z) ? '1' : '0'); } b[y] = 0; return b; }
之前发布的答案都不是我想要的,所以我写了一个.使用%B非常简单printf
!
/* * File: main.c * Author: Techplex.Engineer * * Created on February 14, 2012, 9:16 PM */ #include#include #include #include #include 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]); //Beginning of 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 of 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); }
一些运行时支持"%b",尽管这不是标准.
另见这里有趣的讨论:
http://bytes.com/forum/thread591027.html
HTH
此代码应满足您最多64位的需求.我创建了2个函数pBin&pBinFill.两者都做同样的事情,但是pBinFill用fillChar填充前导空格.测试功能生成一些测试数据,然后使用该功能将其打印出来.
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
是否有printf转换器以二进制格式打印?
该printf()
系列只能使用标准说明符直接在基数8,10和16中打印.我建议创建一个函数,根据代码的特定需要将数字转换为字符串.
在任何基地打印[2-36]
到目前为止,所有其他答案至少具有这些限制之一.
使用静态内存作为返回缓冲区.这限制了函数可用作参数的次数printf()
.
分配需要调用代码释放指针的内存.
要求调用代码显式提供合适的缓冲区.
printf()
直接打电话.这迫使新的功能来fprintf()
,sprintf()
,vsprintf()
等.
使用减小的整数范围.
以下没有上述限制.它确实需要C99或更高版本并使用"%s"
.它使用复合文字来提供缓冲区空间.它在多个呼叫中没有问题printf()
.
#include#include #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, 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 return s; } #include 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
C标准库中没有格式化函数来输出这样的二进制文件.printf系列支持的所有格式操作都是针对人类可读的文本.
也许有点OT,但是如果你需要这个只是为了理解或回溯你正在做的一些二进制操作,你可以看看wcalc(一个简单的控制台计算器).使用-b选项可以获得二进制输出.
例如
$ wcalc -b "(256 | 3) & 0xff" = 0b11
以下递归函数可能很有用:
void bin(int n) { /* Step 1 */ if (n > 1) bin(n/2); /* Step 2 */ printf("%d", n % 2); }