简体   繁体   中英

How does casting uint8* to uint32* work?

There is a member function here :

uint8* CIwTexture::GetTexels() const;

How does casting work here if the return value is cast to uint32* , for example? How can a pointer to 8-bit data can be cast to 32-bit, if the return value is just 8-bit?

Pointers are merely variables with addresses as their values. That means all pointers have the same size (with is not to be confused with "all pointers' data have the same size", which is not true).

All the information the compiler needs to treat the data pointed to by the pointer is inferred from its type. That means that data pointed to by a uint32_t will be treated as 32-bit data, and uint8_t will be treated as 8-bit data.

All this information is only kept at compile-time , and the compiler generates the machine code according to the pointer it is dealing with. That means casting from a pointer to the other is only relevant to the compiler , so it knows how to treat the data when generating code. On runtime, nothing changes, no values are copied or moved.

Roughly, you memory layout may look like this: 初始内存布局

The bracket part(the size of the data) is a hint to the compiler so it can treat the data as intended by the programmer.

When you cast to a uint32_t , your memory layout will roughly look like this: 在此处输入图片说明

Now, that are some things you might infer from this:

  • Your pointer didn't change at all. It still points to the same location.
  • Your memory layout also didn't change. Your data is still there, and so is the other stuff.
  • The pointer's data size did change, but this information is only kept at compile-time, so your program's memory layout didn't really change at all.

Finally, consider the implications of accessing this data as 32-bit:

  • The "Other Stuff" may be other parts of your own program, and if you modify the value bad things will happen.
  • The "Other Stuff" may not belong to your program at all, witch means it will be invading memory that does not belong to it. Again, bad things will happen.
  • Maybe the "Other Stuff" are perfectly valid data for the program to access and modify. This should be clearly documented.

How the casting work here if it's casted to uin32* for example? I mean how a pointer to 8bit data can be casted to 32bit, if the the return is just 8bits ?

It returns a memory address, not 8 bits stored at that memory address. That address points somewhere in memory. When you assign it to uint32* it still points to the same memory location.

Now, when you dereferrence this pointer, it will read value from 4 consecutive memory locations from the address where pointer points to (compare this to the situation where you would dereference uint8 and it would read only one).

// somewhere in the memory
uint32 x;

uint8_t* foo()
{
    // Now imagine here x being constructed from 
    // individual bytes or somehow 
    // ...

    // return pointer to the first byte of x as `uint8_t`
    return (uint8_t*)&x;
}

Now, the problem here is on the caller side - there's nothing in the function signature that tells the caller he needs/can to treat this as a uint32_t . In this case, this must be documented explicitly.

The return value is a pointer to a uint8. A pointer in C++ can be casted into any other kind of pointer. The "magic" starts when you dereference this pointer - and the value returned from the dereferencing is the type of the pointer. For example, if you do:

uint32* ptr = (uint32*)functionThatReturnsPtrToUint8();
uint32 value = *ptr;

Then the "value" variable will just take the first 4 bytes pointed by ptr, and convert them to a uint32 value (how exactly this is done depends on the underlying system endian).

The return is not 8bits. The return is a pointer (a memory address). The type of the pointer tells the compiler how to look a the memory. In this case, it says that the memory should be treated one byte at a time. If you cast the pointer to uint32* you are telling the compiler to treat the data in chunks of four bytes. However, the function returned a pointer to bytes for a reason. The data was probably not intended to be treated in chunks of four bytes. If you cast the pointer to a different type, you are telling the compiler to use the data in a way that was probably not intended.

Pointer is just address, casting the type does not change the address (pointer's value) but give a hint to the compiler.

However when you cast pointer to different types you have the alignment problem, and the compiler will complain. The root issue is the for some architecture you must access memory with proper alignment, for example you cannot de-reference odd address or otherwise the CPU may fault/trap.

This may be safely ignored if you know what you are doing (in this case, I assume the returned pointer is proper aligned).

Last, to cast the pointer you just do:

uint32_t* p = (uint32_t*) mem;

or

uint32_t* p = static_cast<uint32_t*>( mem );

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

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