我有一个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
。
答案 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