C 两个复制位与长字符不同的双字符打印方式不同
如下面的代码所示,我正在尝试使用不同的方法将位从longC 两个复制位与长字符不同的双字符打印方式不同,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;
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;