我正在尝试使用printf
来将double的二进制表示形式打印到控制台上。这是我到目前为止的代码:
#include <stdio.h>
int main()
{
double a = 4.75;
unsigned long long b = *(unsigned long long *) &a;
printf("Double a = %f (0x%x)" a, b);
}
我还尝试将其从很长很长的时间更改为很长的时间。这是我在gcc linux中执行此操作的结果:
Double a = 4.750000 (0x0)
我很确定,因为我的系统是低端字节序的,所以它只捕获所有为零的前32位。但是,我不确定如何解决此问题。
我认为可能是因为linux中long是64位,但是经过测试,我再次得到了相同的结果。也许我打印不正确?不确定,请告诉我,谢谢您的时间。
答案 0 :(得分:3)
在C语言中,类似
unsigned long long b = *(unsigned long long *) &a;
是非法的,因为它违反了一种称为严格别名的规则,该规则涉及一种引用不同类型对象的一种类型的指针。
但是,有一个例外: char指针可以为任何对象起别名
因此,使用char指针,您可以在C语言中执行以下操作:
#include <stdio.h>
int main()
{
double a = 4.75;
unsigned char* p;
// Method 1 - direct memory read
p = (unsigned char*)&a;
for (size_t i=0; i < sizeof(double); ++i)
{
printf("%02x ", *p);
++p;
}
printf("\n");
// Method 2 - reversed memory read
size_t i = sizeof(double);
p = (unsigned char*)&a + i - 1;
do
{
printf("%02x ", *p);
--p;
--i;
} while(i > 0);
return 0;
}
输出:
00 00 00 00 00 00 13 40
40 13 00 00 00 00 00 00
这两种方法以不同的字节序打印。
如果您不喜欢指针,则可以选择使用联合。喜欢:
#include <stdio.h>
int main()
{
union
{
double a;
char c[sizeof(double)];
} d;
d.a = 4.75;
for (size_t i=0; i < sizeof(double); ++i)
{
printf("%02x ", d.c[i]);
}
printf("\n");
size_t i = sizeof(double);
do
{
--i;
printf("%02x ", d.c[i]);
}
while (i > 0);
printf("\n");
return 0;
}
输出:
00 00 00 00 00 00 13 40
40 13 00 00 00 00 00 00
答案 1 :(得分:3)
您的代码有两个问题,一个简单的问题是您使用了错误的格式说明符%llx
是 unsigned long long 的正确说明符。 clang和gcc都使用-Wall
,see it live对此提供了警告。
第二个问题是您在这里违反了strict aliasing rule:
unsigned long long b = *(unsigned long long *) &a;
(在C和C ++中)键入Pun的正确方法是使用memcpy(see it working live):
std::memcpy( &b, &a, sizeof(double));
在上述C ++ 20中的严格别名链接中,我们应该获得bit_cast
,它将简化类型化对等操作,例如:
b = bit_cast<unsigned long long>(a);
答案 2 :(得分:2)
在C ++中:
double a = 4.75;
char tmp[sizeof(double)];
memcpy(tmp, &a, sizeof(double));
... // print individual bytes as hex
或者:
double a = 4.75;
unsigned char* tmp = reinterpret_cast<unsigned char*>(&a);
for (int i = 0; i < sizeof(double); i++)
... // print *(tmp + i) as hex