简体   繁体   中英

What's the difference between these pointer dereferencements

This is the kind of questions where you are sure it is a duplicate but you need to ask. I don't know the terminology so I don't know what to search for, I'm just asking for the right terminology based on the example I give.

Can someone explain me the difference (well, even just the correct terminology and I can google the difference myself) between these 2:

UINT32 v32;
UINT32* v32_ptr = &v32;

UINT16 v16_1 = *(UINT16*)v32_ptr; // Version 1 of dereferencement
UINT16 v16_2 = (UINT16)*v32_ptr; // Version 2 of dereferencement

The result is the same, but what about the use cases?

In the first case, you are casting a 32bit pointer to a 16bit pointer and dereferencing that. In the second case you are dereferencing a 32bit pointer.

In both situations, you are assigning to a 16bit variable.

The results are not always the same, it depends on the architecture endian-ness. In other words, if the architecture is little-endian, then the two 16bit variables should be equal over the entire range of values that the source can take. But if the architecture is big-endian, the values will often be different.

EDIT In light of your question in the comments below, I thought an example would be helpful here.

Consider the following and pretend the architecture can choose which endian it likes. Also, let's use the value 0x4241, and have the process write it out 4 times alternating big/little-endian, the first two times as UINT32 and the last two times as UINT16.

address     data
0xABCD0000  00 00 42 41 // big-endian, UINT32, value 0x4242
0xABCD0004  41 42 00 00 // little-endian
0xABCD0008  42 41       // big-endian UINT16
0xABCD000A  41 42       // little-endian UINT16

The last two are to help visualize the differences.

When we set v32_ptr to the address of v32 it receives the memory address 0xABCD0000 (for example). The value is layed out BE in memory. If we cast v32_ptr to a (UINT16*), the memory address does not change, but now only the first two bytes are used. Dereferencing that pointer as a 16bit pointer would yield 0. But dereferencing it as a 32bit ptr would yield the result 0x4241.

Now do the same with the little-endian variables. Here our memory addresses are 0xABCD0004 and 0xABCD000A. Setting v32_ptr to 0xABCD0004, and dereferencing it as a (UINT16*)(LE) you get the value 0x4241. That is the same value you would get if you dereferenced a 16bit-LE pointer (like at address 0xABCD000A).

Both casts will truncate the 32bit original value, but I hope you can see now the difference.

Lastly

This information has application in network programming, embedded systems, and peer-to-peer and client-server protocols. Little-endian is almost universal, but there are still system that are BE. Also, some older network protocols explicitly chose to use BE. And, a specific application of your example could be to test the endian-ness of the system you are running on (for portable source code). Ie, set v32 = 0x4241, then after dereferencing both ways, if v16_1 and v16_2 are the same (they both equal 0x4241), then the system is LE, but if they are different (one yields 0x4241 and the other yields 0), then the system is BE.

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