在C语言中显示一个数字的二进制表示形式?

8
8个回答

29

没有直接的方式(例如使用printf或其他标准库函数)来打印它。你必须编写自己的函数。

/* This code has an obvious bug and another non-obvious one :) */
void printbits(unsigned char v) {
   for (; v; v >>= 1) putchar('0' + (v & 1));
}

如果你使用终端,可以使用控制代码按自然顺序打印字节:

void printbits(unsigned char v) {
    printf("%*s", (int)ceil(log2(v)) + 1, ""); 
    for (; v; v >>= 1) printf("\x1b[2D%c",'0' + (v & 1));
}

4
不错的位运算技巧。难以阅读的代码太棒了! - Chris Lutz
1
@Chris Lutz:我同意dirkgently的观点。该函数命名得很好,而且以线性方式清晰地编写。每个语句都简单明了。 - abelenky
1
我点了赞,实际上我确实喜欢这个解决方案。有时候我只是有点讽刺。很抱歉似乎让你觉得我认为它不好。如果你懂位运算的话,我认为它非常易读。可惜很多人不懂。 (另外,对我来说,>>= 和 <<= 运算符看起来有点傻。) - Chris Lutz
7
显而易见的错误是它倒序打印了比特。不太明显的错误是当v=0时它没有输出任何内容。 - Chris Lutz
我仍然不理解这个“for”。 - David 天宇 Wong
显示剩余11条评论

26

基于dirkgently的答案,但修复了他的两个错误,并始终打印固定数量的数字:

void printbits(unsigned char v) {
  int i; // for C89 compatability
  for(i = 7; i >= 0; i--) putchar('0' + ((v >> i) & 1));
}

4
作为锦上添花的补充,您还可以将 i = 7 替换为 (sizeof(v)*8)-1。 - Leon
如果我能找到一种方法使函数接受任何类型的参数而不仅仅是无符号字符,我会这样做。我尝试使用void指针,但出现了错误。不过,我以后需要更深入地研究这个问题。 - Chris Lutz
这是我的解决方案:char* printbits(int v) { for(int i = (sizeof(v)*8)-1; i >= 0; i--) putchar('0' + ((v >> i) & 1)); } - David Xia
有没有办法让它返回 char*? - David Xia
@David - 当然有。在谷歌上搜索其他相关问题(或者提出自己的问题,但我打赌它是重复的)。你可能需要使用malloc - Chris Lutz
还要考虑 i = v ? (int)floor(log2(v)) : 0 - DanSkeel

14

可以(自己编写),编写一个像下面这样的完整函数。

#include <stdio.h> /* only needed for the printf() in main(). */
#include <string.h>

/* Create a string of binary digits based on the input value.
   Input:
       val:  value to convert.
       buff: buffer to write to must be >= sz+1 chars.
       sz:   size of buffer.
   Returns address of string or NULL if not enough space provided.
*/
static char *binrep (unsigned int val, char *buff, int sz) {
    char *pbuff = buff;

    /* Must be able to store one character at least. */
    if (sz < 1) return NULL;

    /* Special case for zero to ensure some output. */
    if (val == 0) {
        *pbuff++ = '0';
        *pbuff = '\0';
        return buff;
    }

    /* Work from the end of the buffer back. */
    pbuff += sz;
    *pbuff-- = '\0';

    /* For each bit (going backwards) store character. */
    while (val != 0) {
        if (sz-- == 0) return NULL;
        *pbuff-- = ((val & 1) == 1) ? '1' : '0';

        /* Get next bit. */
        val >>= 1;
    }
    return pbuff+1;
}

在最后添加这个main函数以查看它的运行情况:

#define SZ 32
int main(int argc, char *argv[]) {
    int i;
    int n;
    char buff[SZ+1];

    /* Process all arguments, outputting their binary. */
    for (i = 1; i < argc; i++) {
        n = atoi (argv[i]);
        printf("[%3d] %9d -> %s (from '%s')\n", i, n,
            binrep(n,buff,SZ), argv[i]);
    }

    return 0;
}

使用命令 "progname 0 7 12 52 123" 运行它,将会得到:

[  1]         0 -> 0 (from '0')
[  2]         7 -> 111 (from '7')
[  3]        12 -> 1100 (from '12')
[  4]        52 -> 110100 (from '52')
[  5]       123 -> 1111011 (from '123')

1
如果binrep()函数没有足够的空间来打印它所表示的值,我会看到缓冲区下溢。并且,从痛苦(但很久以前)的经验来看,写入数组前面的内容可能非常难以调试! - Jonathan Leffler
是的,那会很麻烦 - 如果您的整数超过32位,您必须确保增加SZ以适应。 - paxdiablo
修复以防止缓冲区溢出。 - paxdiablo
“buff: buffer to write to must be >= sz+1 chars.” - 这里的sz是缓冲区的大小,不包括终止符。请确保写入的缓冲区大小为sz+1或更大。 - paxdiablo
@Pax:哦,好的...我会删除我的评论。当我遇到一个带有字符串大小参数的函数与简单的sizeof不兼容时,我会感到不适;在我看来,需要记住添加或减去1是不酷的。 - unwind
好吧,它在fgets()中有先例,所以我想这不是完全的反模式。 - paxdiablo

6
#include<iostream>
#include<conio.h>
#include<stdlib.h>
using namespace std;
void displayBinary(int n)
{
       char bistr[1000];
       itoa(n,bistr,2);       //2 means binary u can convert n upto base 36
       printf("%s",bistr);

}

int main()
{
    int n;
    cin>>n;
    displayBinary(n);
    getch();
    return 0;
}

4
使用查找表,例如:
char *table[16] = {"0000", "0001", .... "1111"};

然后像这样打印每个四位二进制数:
printf("%s%s", table[a / 0x10], table[a % 0x10]);

当然,您可以只使用一个表格,但它会稍微快一些并且太大了。

3

在C语言中没有直接的格式说明符。不过,我编写了这个快速的Python代码片段,以帮助您逐步了解如何自己创建。

#!/usr/bin/python

dec = input("Enter a decimal number to convert: ")
base = 2
solution = ""

while dec >= base:
    solution = str(dec%base) + solution
    dec = dec/base
if dec > 0:
    solution = str(dec) + solution

print solution

解释:

dec = input("输入一个十进制数字以进行转换:") - 提示用户输入数字(在C语言中,有多种方法可以通过scanf等方式实现)

base = 2 - 指定我们的基数为2(二进制)

solution = "" - 创建一个空字符串,用于将我们的解决方案连接起来

while dec >= base: - 当我们的数字大于输入的基数时

solution = str(dec%base) + solution - 获取数字对基数的模数,并将其添加到我们字符串的开头(我们必须使用除法和余数法从右到左添加数字)。str()函数将操作结果转换为字符串。在Python中,如果不进行类型转换,则无法将整数与字符串连接。

dec = dec/base - 将十进制数除以基数,以准备进行下一个取模运算

if dec > 0: solution = str(dec) + solution - 如果还有剩余的数字,将其添加到开头(如果有剩余,这将是1)

print solution - 打印最终数字


你忽略了当输入为0的情况,这种情况下不会打印任何内容。 - Kevin Lacquement
我认为没有人会费心将0放入转换器中,因为答案是显而易见的,但可以选择您喜欢的修复方式。在脚本顶部加上if语句,以及sys.exit或在底部检查解决方案变量的值。 - John T

3

这段代码应该可以处理你的需求,最高可达64位。



char* pBinFill(long int x,char *so, char fillChar); // version with fill
char* pBin(long int x, char *so);                    // version without fill
#define width 64

char* pBin(long int x,char *so)
{
 char s[width+1];
 int    i=width;
 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[width+1];
 int    i=width;
 s[i--]=0x00;   // terminate string
 do
 {
  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[width+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

2

您需要编写自己的转换函数。目前只支持使用格式说明符来表示十进制、十六进制和八进制数字。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接