繁体   English   中英

C ++。 从两倍的reinterpret_cast转换为无符号字符*

[英]C++. reinterpret_cast from double to unsigned char*

我今天在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;

所以这是我的第一个问题。 但是,然后我尝试了以下操作,发现它返回了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 ++中使用字符串已经很长时间了,有时候回到原始字符数组时,您会忘记这些事情。

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

为什么最初被吓到返回15? 为什么这4个strick呼叫的大小会增加? 为什么循环返回11、11、11、11?

谢谢。

strlen通过遍历数组(假定传递的const char*指向该数组)直到找到一个值为0的char来工作。这是一个以空字符结尾的字符,该字符自动添加到字符串文字的末尾。 组成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

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

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

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

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

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

有两件事:

  1. sizeof(double)可能不是4。通常是8。请使用运算符,而不要使用硬编码的假设。
  2. 指针reinterpret_cast<unsigned char*>(&d)并不表示指向以空字符结尾的“字符串”的指针。 strlen通过迭代直到找到null进行操作。 您在那里陷入不确定的行为。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM