首页 > 解决方案 > 需要帮助理解在 C 中将双精度转换为二进制的代码

问题描述

所以下面是一些我用来理解如何在 C 中获取 double 的二进制文件的代码,但是代码的某些区域对我来说没有意义,我尝试使用 print 语句来帮助我,但无济于事

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

void double_to_bits(double val);

int main(void)
{
    unsigned idx;

    double vals[] = { 10 };

    for (idx = 0; idx < 4; idx++ ) {
        printf("\nvals[%u]= %+lf-->>", idx, vals[idx] );
        double_to_bits(vals[idx] );
    }
    printf("\n");

    return 0;
}

void double_to_bits(double val)
{
    unsigned idx;
    unsigned char arr[sizeof val];

    memcpy (arr, &val, sizeof val);
    printf("array is : %s\n", arr);

    for (idx=CHAR_BIT * sizeof val; idx-- ; ) {
        putc(
                ( arr[idx/CHAR_BIT] & (1u << (idx%CHAR_BIT) ) )
                ? '1'
                : '0'
                , stdout
        );
    }
}

arr[idx/CHAR_BIT] 返回什么?我知道如果 idx = 63 那么我们得到 arr[7] 但在打印语句中,这些似乎只是给出随机整数值。

还有为什么 arr[idx/CHAR_BIT] 和 (1u%CHAR_BIT) 之间的 & 操作数会给出 2 个奇怪的字符符号?& 操作数如何作用于这两个值?

感谢您的时间和帮助。

标签: cbinarydoublebit

解决方案


此代码定义vals为具有一个元素:

    double vals[] = { 10 };

这段代码vals就像它有四个元素一样使用:

    for (idx = 0; idx < 4; idx++ ) {
        printf("\nvals[%u]= %+lf-->>", idx, vals[idx] );
        double_to_bits(vals[idx] );
    }

因此,程序的行为不是由 C 标准定义的,不同的编译器会做不同的事情。你没有向我们展示你得到了什么输出,所以我们无法分析你的编译器做了什么。我似乎认为,由于vals只有一个元素,它永远不需要计算idxin的值vals[idx];它可以随时使用vals[0]。所以每次迭代都对值 10 进行操作。您的编译器可能已经从数组外部的内存中加载并使用了不同的值。

arr[idx/CHAR_BIT] 返回什么?

CHAR_BIT被定义<limits.h>为一个字节中的位数。由于定义unsigned char arr[sizeof val];, arr是一个数组,其元素(每个字节)与 a 中的字节数一样多double。因此,例如,如果一个字节中有 8 位,a 中有 8 个字节double,则arr有 8 个 8 位元素,总共 64 位。

使用这些示例数字,for循环遍历idx从 63 到 0 的数字。然后代码idx用作 中位的计数器arr。表达式idx/CHAR_BIT计算出数组的哪个元素包含编号的位idx:每个数组元素都有CHAR_BIT位,位 0-7(当CHAR_BIT为 8)在元素 0 中,位 8-15 在元素 1 中,位 16-23 在元素中2,以此类推。因此,除以idxCHAR_BIT截断为整数(这是/运算符对整数操作数所做的)给出了具有 number 位的数组元素的索引idx

然后arr[idx/CHAR_BIT]得到那个元素。然后我们需要从该元素中挑选出单个位。idx%CHAR_BITidx除以的余数CHAR_BIT,因此它给出一个字节内的位数。然后1u << (idx%CHAR_BIT)将该数字移 1。结果是数字,当以二进制表示时,具有该数字的位为 1,其他位为 0。

然后&运算符将其与数组元素进行与运算。如果数组元素有一个 0,其中 1 已移动到,则结果为零。如果数组元素有一个 1,其中 1 已移动到,则结果是该位(仍在其位置)。

然后? '1' : '0;'使用 AND 的结果来选择字符“1”(如果结果不为零)或字符“0”(如果结果为零)。该字符被传递给putc打印。

我知道如果 idx = 63 那么我们得到 arr[7] 但在打印语句中,这些似乎只是给出随机整数值。

当上述数组边界问题得到纠正并double_to_bits传递了一个有效值时,它应该打印对double. 在大多数 C 实现中,这将是 0100000000100100000000000000000000000000000000000000000000000000,这是 IEEE-754 binary64 格式的编码,也称为双精度。

还有为什么 arr[idx/CHAR_BIT] 和 (1u%CHAR_BIT) 之间的 & 操作数会给出 2 个奇怪的字符符号?

您没有显示奇怪的字符符号或其他输出,因此我们没有要解释的输出。

该语句printf("array is : %s\n", arr);打印arr时就好像它是一个包含可打印字符的字符串,但它用于包含“原始二进制数据”,因此您不应期望该数据在打印时会产生有意义的字符。删除该声明。此外,您的程序越界访问的事实vals可能会导致输出中的其他复杂情况。


推荐阅读