Kan
Kan

Reputation: 539

Cast unsigned short * to unsigned int *

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

Answers (3)

Yakk - Adam Nevraumont
Yakk - Adam Nevraumont

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.

  1. A 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".

  1. In some cases, a pointer to the prefix of one type can be used to read another type.

This is known as "layout compatible", and the rules are specific and less generous than most people think.

Upvotes: 9

FalcoGer
FalcoGer

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

eerorika
eerorika

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

Related Questions