今天我正在玩一个关于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?
感谢。
答案 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)
有几件事:
sizeof(double)
可能不是4.通常是8.使用运算符而不是硬编码假设。reinterpret_cast<unsigned char*>(&d)
未指示指向以null结尾的“字符串”的指针。 strlen
通过迭代操作直到找到null。你在那里遇到了未定义的行为。