C 两个复制位与长字符不同的双字符打印方式不同

C 两个复制位与长字符不同的双字符打印方式不同,c,pointers,casting,bit-manipulation,type-punning,C,Pointers,Casting,Bit Manipulation,Type Punning,如下面的代码所示,我正在尝试使用不同的方法将位从longlongnum复制到两个double,d1和d2,分别使用指针转换+解引用和“按位和” # include <stdio.h> int main(void) { long longnum = 0xDDDDDDDDDDDDDDDD; double d1 = *((double*)(&longnum)); double d2 = longnum & 0xFFFFFFFFFFFFFFFF;

如下面的代码所示,我正在尝试使用不同的方法将位从long
longnum
复制到两个double,
d1
d2
,分别使用指针转换+解引用和“按位和”

# include <stdio.h>

int main(void) {
    long longnum = 0xDDDDDDDDDDDDDDDD;
    double d1 = *((double*)(&longnum));
    double d2 = longnum & 0xFFFFFFFFFFFFFFFF;

    printf("%ld\n\n",longnum);
    printf("%lf\n\n",d1);
    printf("%lf\n",d2);
    return 0;
}
考虑到
DBL_MAX
的大小,一个双精度的最大大小,在我看来,这是一个巨大的数字,实际上是两个双精度打印的合理输出

double d2 = longnum & 0xFFFFFFFFFFFFFFFF;
&
掩码不起任何作用。与所有1和的数字是相同的数字。上面的行与以下行没有区别:

double d2 = longnum;
这句话没有做任何重新解释。相反,它将
d2
设置为最接近
longnum
中值的
double
。该值将是相似的;位模式将完全不同

做你想做的事最好的方法就是和工会合作。工会是最好的表现方式

像使用
d1
那样使用指针在技术上会调用未定义的行为。这是一个常见的习惯用法,在实践中可能会很好,但应该避免使用指针键入双关语。

您的问题是

d1 = *((double*)(&longnum));
通过执行上述操作,您将错误地从内存中获取内容,然后假定其为双精度格式

如果您通过以下方式执行此操作:

d1 = (double) longnum;
然后,内存空间longnum(8字节整数)的内容被正确转换,然后正确存储在d1所指位置的内存中。 然后d1的内容将是正确的。 建议您阅读关于“双精度浮点格式”的维基百科页面

浮点值(或双精度值)的值在内存中的存储方式与整数的存储方式不同。

由于严格的别名规则,它无论如何都是UB。
long
不需要与
double
的大小相同。1)您应该使用正确大小的无符号固定宽度类型。并使用
\u Static\u assert
确保
double
具有相同的大小。它仍将由实现定义,但至少不会调用未定义的行为。“联合是最直接的方式”-实际上,如果没有一种类型是
char
,它们是唯一的兼容方式。但这种类型的puning是非法的。不要建议使用它。@EugeneSh.:嗯?该标准明确允许它作为
union
s的一个应用程序。当然,它是所有实现定义的。但是它没有定义
u.l=5的结果;printf(“%lf”,u.d.)
我认为即使不是具体实现,只要
long
double
大小相同,union方法也是有效的。这不会复制位,而是复制值。我相信其目的是复制位。它将进行
long
->
double
转换,而不仅仅是重新解释位模式。完全不同的事情。
d1 = *((double*)(&longnum));
d1 = (double) longnum;