C ++。 reinterpret_cast从double到unsigned char *

时间:2013-04-03 15:13:37

标签: c++ char double reinterpret-cast

今天我正在玩一个关于C ++的小游戏并遇到过这个我觉得奇怪的事情,但也许更可能是由于我的误解和最近缺乏纯C编码。

我原本打算做的是将double转换为无符号字符数组。我的理解是double的64位(sizeof(double)是8)现在将表示为8个8位字符。为此,我使用了reinterpret_cast。

所以这里有一些代码可以从double转换为char数组,或者至少我认为这就是它正在做的事情。问题是它从strlen返回15而不是8,为什么我不确定。

double d = 0.3;

unsigned char *c = reinterpret_cast<unsigned char*> ( &d );

std::cout << strlen( (char*)c ) << std::endl;

所以strlen是我的第一个问题。但后来我尝试了以下内容,发现它返回了11,19,27,35。这些数字之间的差异是8,所以在某种程度上正确的事情正在发生。但为什么这不会返回15,15,15,15,(因为它在上面的代码中返回15)。

double d = 0.3;
double d1 = 0.3;
double d2 = 0.3;
double d3 = 0.3;

unsigned char *c_d = reinterpret_cast<unsigned char*> ( &d );
unsigned char *c_d1 = reinterpret_cast<unsigned char*> ( &d1 );
unsigned char *c_d2 = reinterpret_cast<unsigned char*> ( &d2 );
unsigned char *c_d3 = reinterpret_cast<unsigned char*> ( &d3 );

std::cout << strlen( (char*)c_d ) << std::endl;
std::cout << strlen( (char*)c_d1 ) << std::endl;
std::cout << strlen( (char*)c_d2 ) << std::endl;
std::cout << strlen( (char*)c_d3 ) << std::endl;

所以我查看了字符的地址,它们是。

0x28fec4
0x28fec0
0x28febc
0x28feb8 

现在这是有意义的,因为我的系统上的unsigned char *的大小是4个字节,但我认为将从强制转换中分配正确的内存量,否则看起来reinterpret_cast是一个非常危险的事情。 。此外,如果我做

for (int i = 0; i < 4; ++i) {
    double d = 0.3;

    unsigned char *c = reinterpret_cast<unsigned char*> ( &d );

    std::cout << strlen( (char*)c ) << std::endl;
}

这会打印11,11,11,11!

所以这里发生了什么,很明显,内存会被覆盖,并且重新解释强制转换并不像我想象的那样工作(即我使用它错了)。在C ++中使用字符串这么长时间,有时当你回到原始字符数组时,你会忘记这些事情。

所以我认为这是一个3部分问题。

为什么strlen最初会回来15? 为什么4个strlen调用的大小增加? 为什么循环返回11,11,11,11?

感谢。

3 个答案:

答案 0 :(得分:11)

strlen通过迭代遍历它假定传递const char*点的数组来工作,直到它找到值为0的char。这是自动添加的空终止字符到字符串文字的末尾。组成double的值表示的字节不以空字符结尾。 strlen将继续超过double对象的末尾,直到找到值为0的字节。

考虑字符串文字"Hello"。在内存中,使用ASCII兼容的执行字符集,它将存储为以下字节(十六进制):

48 65 6c 6c 6f 00

strlen会读取每个字符,直到找到值为0的字节并报告到目前为止已经看到的字节数。

0.3的IEEE 754双精度表示法是:

3F D3 33 33 33 33 33 33

如您所见,没有值为0的字节,因此strlen只是不知道何时停止。

函数返回的任何值可能只是它在内存中找到0之前得到的距离,但是你已经达到了未定义的行为,所以对它进行任何猜测都是没有意义的。

答案 1 :(得分:6)

您的问题是您使用strlen( (char*)c ),因为strlen需要一个指向以null结尾的字符串的指针。

看起来你期望在第8个字节和第9个字节之间存在某种“边界”,因为前8个字节原来是double

一旦将内存转换为char*,该信息就会丢失。您的代码有责任了解有多少char有效。

答案 2 :(得分:2)

有几件事:

  1. sizeof(double)可能不是4.通常是8.使用运算符而不是硬编码假设。
  2. 指针reinterpret_cast<unsigned char*>(&d)未指示指向以null结尾的“字符串”的指针。 strlen通过迭代操作直到找到null。你在那里遇到了未定义的行为。