Reputation: 539
I'm learning c++ and I had a question about cast. I have an unsigned short * and i want cast it into a unsigned int * but i don't have the same value and i wanna know why.
When i cast a short into an int (with static cast) i have the same value but it don't works for unsigned short * to unsigned int *
So i try to understand why ! A short is 4 bytes and an int can be 8, 16 or 32. So the pointer goes everytime to far into the memory ? But why does a cast from short into int works ?
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)
The results is different ... Can someone explain me why and how to cross this problem ?
Thanks a lot,
Upvotes: 3
Views: 4578
Reputation: 275385
Casting one kind of pointer to another in C++ and then dereferencing it is "undefined behavior"; you aren't allowed to do it and expect sane results.
In this specific case, the cast is basically doing a reinterpretation of the bytes of data at the address pointed to. The problem, at the level of machine code produced, is that int
requires 4 bytes on your system, while short
is only 2; so you read past the end of the short
and get garbage data.
There are also problems at higher abstractions than the machine code produced (the aformentioned undefined behavior does not mean "well, you read the wrong memory", that is a tame possibility; truely crazy things can happen, including time travel, and that is not a joke). But that is sufficient.
When you cast an actual int
to a short
(or the unsigned equivalent) the language actually takes the contents of the short
and extends it to fill the int
.
There is no way to take an unsigned short*
and, without creating an independent resource to point to, get an unsigned int*
.
Pointers in C++ are like street addresses. An int
is an office building, a short
is a bungalo. If you have the address of a bungalow, and you scribble on it "this is an office building", it doesn't make it true. And when someone goes to the bungalow and blindly uses the elevator, things go screwy.
On the other hand, if you have a bungalow and say "build this into an office building" (a cast of an actual short to an int), that can be done. You get a different building (as the office building doesn't fit on the lot for a bungalow), but it fits everything that fit in the bungalow.
Now, you are usually allowed to convert pointers to less-aligned pointers so long as you convert the pointers back before you use them (!).
In some narrow cases you are allowed to dereference the pointer.
char*
can be used to read the "raw memory" of certain types (and std::byte*
and the like).Writing such bytes to copy an object only works if they are "trivially copyable".
This is known as "layout compatible", and the rules are specific and less generous than most people think.
Upvotes: 9
Reputation: 2457
You can't cast a pointer into another pointer type and expect it to work. The pointer points to the memory location of an unsigned short.
If you need to cast then you must pull the unsigned short out of the memory and put it into another.
// 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;
However when you return a pointer from your function, you can not use the address of an object on the stack (like b& in this case), instead you need to use new
. In that case you should make certain that you also call 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;
Upvotes: 0
Reputation: 238341
unsigned short*
points to a location in memory that contains an object of type unsigned short
. That memory location does not contain an object of type unsigned int
. The behaviour of indirecting through a pointer to one type when an object of that type doesn't exist at the pointed location is in general undefined (there are exceptions for certain types).
Upvotes: 4