【问题标题】:Need help understanding code converting doubles to binary in C需要帮助理解在 C 中将双精度转换为二进制的代码
【发布时间】:2021-12-21 08:25:33
【问题描述】:

所以下面是一些我用来理解如何在 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 个奇怪的字符符号? & 操作数如何作用于这两个值?

感谢您的时间和帮助。

【问题讨论】:

    标签: c binary double bit


    【解决方案1】:

    此代码将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 只有一个元素,它永远不需要计算idxvals[idx] 中的值;它总是可以使用vals[0]。所以每次迭代都对值 10 进行操作。您的编译器可能已经从数组外部的内存中加载并使用了不同的值。

    arr[idx/CHAR_BIT] 返回什么?

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

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

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

    然后&amp; 运算符将其与数组元素进行与运算。如果数组元素有一个 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 的事实可能会导致输出出现其他复杂情况。

    【讨论】:

    • 这太棒了,非常感谢您的帮助。已经清理了很多。
    • 但是,当您说“然后 1u
    • @avii:当idx 是59 并且CHAR_BIT 是8 时,那么idx%CHAR_BIT 是3(59 除以8 的余数)。然后1 &lt;&lt; 3 将 1 移位 3 位,二进制为 1000,即 8。
    猜你喜欢
    • 2018-08-18
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-06-12
    • 1970-01-01
    • 2011-01-14
    • 1970-01-01
    • 2011-07-31
    相关资源
    最近更新 更多