c 整数转二进制数

c integer to binary number

如果有人能帮助我,我将非常高兴...

我应该编写一个程序,在不使用循环的情况下以二进制表示形式打印一个整数。它还需要以 32 位表示形式打印出数字。对于小数字(例如 256 仍然有效),下面的代码工作正常。对于大数字,我没有得到预期的输出。

有人知道我该如何解决这个问题吗?

非常感谢!

#include <inttypes.h>
#include <stdio.h>
#include <stdlib.h>

void
print_reverse(uint32_t value)
{

    if (value % 10 == 0) {
        if (value == 0) {
            printf("1");
            return;
        } else {
            printf("0");
            print_reverse(value / 10);
        }
    } else {
        if (value == 1) {
            return;
        } else {
            printf("1");
            print_reverse((value - 1) / 10);
        }
    }
    return;
}

int
print_binary1(uint32_t value, uint32_t binary1, int zeros1)
{
    int rest, binary, zeros;
    if (value == 0) {
        zeros = zeros1;
        printf("%0*d", 32 - zeros, 0);
        return binary1;
    } else {
        rest = value % 2;
        if (rest >= 1) {
            binary = binary1 * 10 + 1;
            zeros = zeros1 + 1;
            return print_binary1((value - 1) / 2, binary, zeros);
        } else {
            binary = binary1 * 10;
            zeros = zeros1 + 1;
            return print_binary1(value / 2, binary, zeros);
        }
    }
}

void
print_binary(uint32_t value)
{
    printf("%" PRIu32, value);
    if (value == 0) {
        printf(" = 0b00000000000000000000000000000001");
    } else {
        printf(" = 0b");
        int binary = print_binary1(value, 1, 0);
        print_reverse(binary);
    }
}

int
main(void)
{
    uint32_t value;
    printf("value: ");
    if (scanf("%" SCNu32, &value) != 1) {
        fprintf(stderr,
                "ERROR: While reading the 'uint32_t' value an error occurred!");
        return EXIT_FAILURE;
    }
    printf("\n");
    print_binary(value);
    printf("\n");
    return EXIT_SUCCESS;
}

首先,除非您拥有几乎同一行代码的 32 个版本,否则不可能使用循环。

比如题中的代码使用了递归来实现循环。 (其实任何循环都可以用递归来实现。)但是还是在循环(重复执行相同的代码)。

在隐藏循环的同时实现您想要的效果的最简单方法是使用 snprintf


其余部分回答了为什么代码不适用于更大的数字。

看起来这会产生我 previously called "decimal-coded binary" (in reference to binary-coded decimal) 的结果,其中十进制表示的每个数字代表一个位。例如,它将十三(1101 基数 2)转换为一千一百零一(1101 基数 10)。

如果是这样,程序支持的最大输入是 1,1111,1111(基数 2),因为 10,0000,0000(基数 10)不适合 uint32_t。换句话说,32 位输出支持 floor(log10(2^32-1)) = 9 位输入。表示程序支持编号从0到511,但不能超出。

通过切换到 64 位输出,您可以支持 floor(log10(2^64-1)) = 19 位输入,这仍然不足以满足您的需求。

你需要一种不同的方法。

“无循环”是一个愚蠢的约束。如果它是一个编程练习,它可能是有意义的,如果建议是使用一些替代循环,比如递归或循环展开,但这些实际上只是戴着假胡子并以明显编造的口音说话的循环。你需要输出32个字符,你只需要看32位就可以很容易地做到这一点。

无论如何,这是一种无需任何循环的方法,因为我只是展开了循环。 (我不会写 32 条语句,所以我稍微作弊并使用 table)。

// a table for 4-bit numbers to get us started...
char *bits[] = {
    "0000",
    "0001",
    "0010",
    "0011",
    "0100",
    "0101",
    "0110",
    "0111",
    "1000",
    "1001",
    "1010",
    "1011",
    "1100",
    "1101",
    "1110",
    "1111",
};

// brute force, which is essentially loop unrolling
void print_bits_brute(uint32_t i)
{
#define B(offset) bits[(i >> offset) & 0xf]
    printf("0b%s%s%s%s%s%s%s%s\n",
           B(28), B(24), B(20), B(16), B(12), B(8), B(4), B(0));
#undef B
}

展开发生在 print_bits_brute() 中,如您所见,如果只使用一个循环,这会容易得多。这样的循环可能如下所示:

void print_bits_loop(uint32_t i)
{
    printf("0b");
    for (int b = 28; b >= 0; b -= 4)
    {
        printf("%s", bits[(i >> b) & 0xf]);
    }
    printf("\n");
}

它做同样的事情。如果通过展开循环可以获得一些速度,编译器知道如何将循环中的常量转换为适当的东西,因此展开循环可能没有任何好处。

如果你必须递归地做,那很容易。它是另一个名称的循环。好吧,不完全是,因为这段代码不是尾递归的,但它已经足够接近了。

// b must be a power of two here...
void print_bits_b(uint32_t i, int b)
{
    if (b == 4)
    {
        printf("%s", bits[i & 0xf]);
    }
    else
    {
        b >>= 1;
        print_bits_b(i >> b, b);
        print_bits_b(i, b);
    }
}

void print_bits_recursive(uint32_t i)
{
    printf("0b");
    print_bits_b(i, 32);
    printf("\n");
}

一个32位整数可以拆分成两个16位整数。这些 16 位整数可以拆分为四个 8 位整数,它们又可以拆分为八个 4 位整数。那些我们可以直接用 table.

处理的