将 double 的位模式显示为十六进制?
Display bit pattern of double as hex?
我正在尝试使用 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);
}
我也尝试过将它从 long long 改为 long。这是我在 gcc linux:
中这样做的结果
Double a = 4.750000 (0x0)
我很确定,因为我的系统是小尾数法,它只抓取全为零的前 32 位。但是,我不确定如何解决这个问题。
我以为可能是因为 long 在 linux 中是 64 位的,但在测试后我又得到了相同的结果。也许我打印不正确?不确定,让我知道并感谢您的宝贵时间。
在 C 中,代码如下
unsigned long long b = *(unsigned long long *) &a;
是非法的,因为它违反了关于一种类型的指针引用另一种类型的对象的严格别名规则。
但是,有一个例外:一个字符指针可以作为任何对象的别名
所以使用字符指针,你可以在 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
您的代码有两个问题,一个简单的问题是您使用了错误的格式说明符 %llx
是 unsigned long long 的正确说明符。 clang 和 gcc 都为此使用 -Wall
、see it live.
提供警告
第二个问题是你在这里违反了strict aliasing rule:
unsigned long long b = *(unsigned long long *) &a;
输入双关语(在 C 和 C++ 中)的正确方法是使用 memcpy (see it working live):
std::memcpy( &b, &a, sizeof(double));
在 C++20 中的严格别名 link 上面的注释中,我们应该得到 bit_cast
这将简化类型双关,例如:
b = bit_cast<unsigned long long>(a);
在 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
我正在尝试使用 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);
}
我也尝试过将它从 long long 改为 long。这是我在 gcc linux:
中这样做的结果Double a = 4.750000 (0x0)
我很确定,因为我的系统是小尾数法,它只抓取全为零的前 32 位。但是,我不确定如何解决这个问题。
我以为可能是因为 long 在 linux 中是 64 位的,但在测试后我又得到了相同的结果。也许我打印不正确?不确定,让我知道并感谢您的宝贵时间。
在 C 中,代码如下
unsigned long long b = *(unsigned long long *) &a;
是非法的,因为它违反了关于一种类型的指针引用另一种类型的对象的严格别名规则。
但是,有一个例外:一个字符指针可以作为任何对象的别名
所以使用字符指针,你可以在 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
您的代码有两个问题,一个简单的问题是您使用了错误的格式说明符 %llx
是 unsigned long long 的正确说明符。 clang 和 gcc 都为此使用 -Wall
、see it live.
第二个问题是你在这里违反了strict aliasing rule:
unsigned long long b = *(unsigned long long *) &a;
输入双关语(在 C 和 C++ 中)的正确方法是使用 memcpy (see it working live):
std::memcpy( &b, &a, sizeof(double));
在 C++20 中的严格别名 link 上面的注释中,我们应该得到 bit_cast
这将简化类型双关,例如:
b = bit_cast<unsigned long long>(a);
在 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