5

今天我在玩 C++ 时遇到了这个问题,我认为这很奇怪,但可能更可能是由于我的误解和最近缺乏纯 C 编码。

我最初想做的是将双精度转换为无符号字符数组。我的理解是,双精度的 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++ 中使用字符串已经很长时间了,有时当你回到原始 char 数组时,你会忘记这些事情。

所以我想这是一个三部分的问题。

为什么 strlen 最初返回 15?为什么 4 个 strlen 调用的大小变大了?为什么循环返回 11、11、11、11?

谢谢。

4

3 回答 3

11

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

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

48 65 6c 6c 6f 00

strlen将通读它们中的每一个,直到找到具有值的字节0并报告到目前为止它已经看到了多少字节。

IEEE 754 双精度表示0.3为:

3F D3 33 33 33 33 33 33

如您所见,没有带有 value 的字节0,所以strlen不知道何时停止。

无论函数返回什么值,都可能只是它在内存中找到 0 之前的距离,但是您已经遇到了未定义的行为,因此对其进行任何猜测都是毫无意义的。

于 2013-04-03T15:17:29.377 回答
6

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

似乎您期望在第 8 和第 9 个字节之间存在某种“边界”,因为前 8 个字节最初是double.

一旦您将该内存转换为char*. 您的代码有责任知道有多少chars 是有效的。

于 2013-04-03T15:15:58.537 回答
2

有几件事:

  1. sizeof(double)可能不是 4。通常是 8。使用运算符而不是硬编码假设。
  2. 该指针reinterpret_cast<unsigned char*>(&d)不指示指向以空值结尾的“字符串”的指针。strlen通过迭代进行操作,直到找到空值。你在那里陷入了未定义的行为。
于 2013-04-03T15:18:57.167 回答