需要帮助理解在 C 中将双精度数转换为二进制数的代码

Need help understanding code converting doubles to binary in C

所以下面是一些代码,我用它来了解如何在 C 中获取双精度二进制数,但是代码的某些区域对我来说没有意义,我尝试使用 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] return 是什么意思?我知道如果 idx = 63 那么我们得到 arr[7] 但在打印语句中这些似乎只是给出随机整数值 .

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

感谢您的宝贵时间和帮助。

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

What does arr[idx/CHAR_BIT] return?

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

使用这些示例数字,for 循环迭代 idx 从 63 到 0 的数字。然后代码使用 idx 作为 [=21] 中的位的计数器=].表达式 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 << (idx%CHAR_BIT) 按该数字移动 1。结果是一个数字,当以二进制表示时,该数字的位为 1,其他位为 0。

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

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

I understand say if idx = 63 then we get arr[7] but in print statements these seem to just give random integer values .

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

Also why does the & operand between arr[idx/CHAR_BIT] and (1u%CHAR_BIT) give 2 weird character symbols?

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

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