我正在学习c ++,并且对演员表有疑问。 我有一个无符号的short *,我想将其转换为一个无符号的int *,但我没有相同的值,我想知道为什么。
当我将一个short转换为一个int(带有静态转换)时,我具有相同的值,但不适用于unsigned short *到unsigned int *
所以我试图理解为什么! 一个short是4个字节,一个int可以是8、16或32。 那么指针每次都深入内存吗? 但是为什么从short转换为int起作用呢?
unsigned short *a = something(); // something return me a unsigned short *a
unsigned int *b = static_cast<unsigned int *>(a); // I also tried with reintepret_cast
std::cout << *a << std::endl // (print me my first value)
std::cout << *b << std::endl // (print me a wrong value)
结果不同...有人可以解释我为什么以及如何解决这个问题吗?
非常感谢
答案 0 :(得分:6)
在C ++中铸造一种指向另一种的指针,然后对其取消引用是“未定义的行为”;您将被禁止这样做并期望获得理智的结果。
在这种特定情况下,类型转换基本上是对指向的地址处的数据字节进行重新解释。在产生的机器代码级别上,问题是int
在系统上需要4个字节,而short
仅2个字节;因此您读了short
末尾并获得了垃圾数据。
在比生成的机器代码更高的抽象水平上,还存在一些问题(上述未定义的行为不是的意思是“嗯,您读错了内存”,这是一种温和的可能性;确实疯狂的事情可以发生,包括时间旅行,这不是玩笑)。但这足够了。
当您将实际的int
投射到short
(或无符号等效项)时,该语言实际上会获取short
的内容并将其扩展为填充int
无法获取unsigned short*
,并且在不创建指向该资源的情况下获取unsigned int*
。
C ++中的指针就像街道地址。 int
是一栋办公楼,short
是一栋简易别墅。如果您有平房的地址,并且在其上写下“这是一栋办公楼”,那么它就不是真的。当有人去平房盲目地使用电梯时,事情就screwy去了。
另一方面,如果您有一个平房并说“将其建在办公楼中”(实际是一个int的缩写),则可以这样做。您将获得另一座建筑物(因为办公楼不适合平房使用),但它适合平房中的所有建筑物。
答案 1 :(得分:4)
unsigned short*
指向内存中包含unsigned short
类型的对象的位置。该内存位置不包含类型unsigned int
的对象。通常,在指向的位置不存在该类型的对象时,通过指针间接指向一种类型的行为是不确定的(某些类型有例外)。
答案 2 :(得分:0)
您不能将指针转换为其他指针类型并期望它能工作。指针指向无符号short的存储位置。
如果需要强制转换,则必须从内存中拉出unsigned short,然后将其放入另一个。
// in main
unsigned short *ptr_a = something(); // something return me a unsigned short *a
unsigned int b = static_cast<unsigned int>(*ptr_a); // cast the object at a into an uint
unsigned int ptr_b = b&; // get the address for the new object
std::cout << *ptr_a << std::endl;
std::cout << *ptr_b << std::endl;
但是,当您从函数返回指针时,不能使用堆栈上对象的地址(在本例中为b&),而是需要使用new
。在这种情况下,应确保您也致电delete
int* something() {
// int a = 5;
// BAD - DON'T DO THIS: return a&;
int* a = new int;
*a = 5;
return a; // OK, but remember to delete
}
// in some function, eg. main
unsigned short *ptr_a = something(); // something return me a unsigned short *a
unsigned int *ptr_b = new int;
*ptr_b = static_cast<unsigned int>(*ptr_a);
std::cout << *ptr_a << std::endl;
std::cout << *ptr_b << std::endl;
delete ptr_a;
delete ptr_b;