如何在C中打印int作为二进制文件?

时间:2015-01-20 16:00:01

标签: c

我有一个C代码,我想打印所有数字,直到二进制的某个范围。我有以下代码,但打印部分似乎无法正常工作。

#include <limits.h>
#include <stdio.h>
#include <string.h>

#define SIZE UINT_MAX

const char *byte_to_binary(unsigned long int x)
{
    static char b[33];
    b[0] = '\0';

    unsigned long int z;
    for (z = SIZE; z > 0; z >>= 1)
    {
        strcat(b, ((x & z) == z) ? "1" : "0");
    }

    return b;
}

int main(void)
{
    unsigned long int i;

    for (i = 0; i <= SIZE; i++)
    {
        printf("%s\n", byte_to_binary(i));
    }

    return 0;
}

我希望它具有灵活性,所以当我更改SIZE常量时,我​​希望它能正常处理任何值,直到最大整数值为unsigned long int

6 个答案:

答案 0 :(得分:3)

您的SIZE应该只有一个1位作为MSB。 您可以更改程序以实现以下方式:

#define SIZE (UINT_MAX ^ (UINT_MAX >> 1))

答案 1 :(得分:2)

在程序中,有必要知道unsigned long int类型的位数,因为您有兴趣用表示这些位的字符填充char数组。

C中的无符号整数类型需要N + P位,其中N是数字的二进制表示中使用的位数,P是填充位。
填充位的存在对于家庭PC用户来说非常罕见,但是它们不能被遗忘。

另一方面,在C中我们不能确定1字节== 8位 我们只能确保1个字节至少为8位。

因此,像SIZE这样的8*sizeof(unsigned long)之类的预计算会出错。

要获得unsigned long中可表示的最重要位,我们需要使用ULONG_MAX常量关节来处理某些技巧。

 #define MOST_SIGNIF_UL (ULONG_MAX ^ (ULONG_MAX >> 1))  

编辑段落当我输入此答案时,用户 Eugene Sh 首先发布了早期的公式。无论如何,在这篇文章中我解释了其他细节以改进OP的代码。

常量MOST_SIGNIF_UL现在保持二进制值,包括1后跟N - 1个零,N是unsigned long的二进制数字。

这个常量在编译时可以处理,它独立于一个字节中的位数,填充位的存在或不存在,以及底层系统中unsigned long int的字节数。登记/> 如果unsigned long有32个值位,那么上面的常数等于2³¹,从而给出一个二进制对象,其中最高有效位为1,其余为0.

您正在使用static char[]作为阵列 我认为这不是将char数组“导出”给调用者的好方法 可以创建类型为char*的对象(通过为其分配内存)并返回该指针。您可以在需要时“销毁”此对象,只需通过释放其内存即可。

#include <limits.h>  /* Use ULONG_MAX */
#include <stdio.h>

#define MOST_SIGNIF_UL (ULONG_MAX ^ (ULONG_MAX >> 1))

char * byte_to_binary(unsigned long int x)
{
    /* Precomputation of number of bits for unsigned long value bits: */
    /* This piece of code would have to be outside to be computed only once. */
    int bitcount = 0;
    for(unsigned long z = MOST_SIGNIF_UL; z > 0; z >>= 1)
        bitcount++;

    char *b = malloc(bitcount + 1);

    for (unsigned long int k = 0, z = MOST_SIGNIF_UL; z > 0; k++, z >>= 1)
    {
       b[k] = (x & z)? '1' : '0';
    }

    b[bitcount] = '\0';  /* End of string */

    return b;
}

int main(void)
{
  char *str = byte_to_binary(131073); /* Create object str */
  printf("%s", str);
  free(str);                          /* Destroy object str */
  return 0;
}

如您所见,条件运算符只需要评估(x & z)而不是更详细的版本(x & z) == z
原因是z只有第k位“on”(即“1”)而任何其他位“off”(即“0”)。因此,当且仅当x时,(x & z) != 0的第k位为1。

此外,避免使用标头<string.h>,因为省略了函数strcat()(在此上下文中使用strcat()效率不高)。

bitcount的预计算可以在函数之外完成,以获得最佳效率,但我为您留下了这个细节。

答案 2 :(得分:1)

这将适应您在#define中声明的任何类型。

#include <stdio.h>
#include <string.h>

#define mytype unsigned long int

const char *byte_to_binary(mytype x)
{
    static char b[8*sizeof(mytype)+1];
    mytype z = 1 << (8*sizeof(mytype)-1);
    b[0] = 0;
    while (z) {
        strcat(b, (x & z) ? "1" : "0");
        z >>= 1;
    }
    return b;
}


int main(void)
{
    printf("%s\n", byte_to_binary(12345678));
    return 0;
}

我将main()中的循环留给你 - 我无法相信你真的想要打印如此大的范围。

答案 3 :(得分:0)

UINT_MAX将计算无符号整数可以表示的最大值,它将是0xFFFFFFFF(依此类推,直到使用所有位),而不是0x80000000,这是我想要的。

您可以计算出变量中有多少位(即8*sizeof(unsigned long int)),因此您可以从中创建初始掩码,例如

int size = 8 * sizeof(unsigned long int);
for (z = 1 << (size - 1); z > 0; z >>= 1)
{
    strcat(b, ((x & z) == z) ? "1" : "0");
}

答案 4 :(得分:0)

这是你在没有重置数组的情况下进行多次调用,因此你将得到32个字符为0,然后32个为1,再次为2,依此类推。如果byte不是8位,CHAR_BIT会因为可移植性原因而命中你。假设32位长。 memset整个数组为0。

答案 5 :(得分:-5)

这样的事情可能有用:

template <typename Number>
std::string as_binary(Number n) {
   std::string ret;
   for (size_t i  = (sizeof(n)*8)-1; i >= 0; --i)) {
     ret += ( (n & (1 << i)) ? "1" : "0"  )
  }
  return ret;
}

<强>更新

好的,前面是用记事本编写的C ++实现,当然它有错误,但用户应该能够纠正它们。我认为这一点,我更喜欢&#34;你可以这样做&#34;整个&#34;这就是方式&#34;的事情。

无论如何,用C语言编写的解决方案可能如下所示(使用int实现,可以轻松更新为任何其他整数类型)

ichramm@hypernova:~$ cat test.c 
#include <stdio.h>
#include <string.h>
#include <assert.h>

char * as_binary(unsigned int n, char *buffer, int size) {
    int i = (sizeof(n)*8);
    assert(i < size);
    memset(buffer, 0, size);
    for (i = i-1; i >= 0; --i) {
        strcat(buffer, (n & (1u << i)) ? "1" : "0" );
    }
    return buffer;
}

int main() {
    char buff[33];
    printf("%d %s\n", 1, as_binary(1, buff, 33));
    printf("%d %s\n", 2, as_binary(2, buff, 33));
    printf("%d %s\n", 4, as_binary(4, buff, 33));
    printf("%d %s\n", 8, as_binary(8, buff, 33));
    printf("%d %s\n", 16, as_binary(16, buff, 33));
    printf("%d %s\n", 31, as_binary(31, buff, 33));
    printf("%d %s\n", 32, as_binary(32, buff, 33));
    return 0;
}

ichramm@hypernova:~$ gcc -g test.c -o test
ichramm@hypernova:~$ ./test 
1 00000000000000000000000000000001
2 00000000000000000000000000000010
4 00000000000000000000000000000100
8 00000000000000000000000000001000
16 00000000000000000000000000010000
31 00000000000000000000000000011111
32 00000000000000000000000000100000