pointer casting

Asked

Viewed 886 times

2

Guys , I can’t understand why casting between pointers has some impact on the code or just to make the code readable as for example this line of a function:

 void* getPhysicalAddress (pdirectory* dir, uint32_t virt) {

   ... 
   ... 

   return (void*) ((uint32_t*) (pagedir[virt >> 22] & ~0xfff))[virt << 10 >> 10 >> 12];


}

What to do (void*)((uint32_t*)(..) for example? I’d like to know when to use the cast of pointers?

2 answers

3


First you must understand what types (int, char, long, etc.) has a size set by the platform, some keeps its size on all platforms, as in the case of type char of 8 bits.

Pointers point to memory address, however, you need to tell what type (size) of memory region you want to point to, so that the compiler knows how to handle the information the pointer points to (allocations, calculations, etc).

The guy void is an exception to the type rules. The type void has the size of 1 byte, however, it does not store any data. The type pointer void can only point to another pointer of the same type (this rule is for all types), usually it is used to "generalize" data. It is widely used for when you do not know what kind of data you will receive, but when you receive it it is necessary to make a cast for the type of variable that is receiving this data, so that it is possible to manipulate it (allocations, calculations, assignments, etc.).

The cast serves to force a variable to be a different type than what it was declared. It is used to optimize operations and even make it possible to operate between two or more variables without the result being something unexpected.

Referring to your line of code, I’ll divide it into four for analysis:

First part:

In this section is made a shift operation of the variable value virt, to take the 10 most significant bits of the data contained in the variable and the resulting value will serve as the index for the array pagedir. Of the value contained in pagedir index [virt >> 22] is made two more operations, one of negation (~) and one AND (&) and will result in another value, which seems to me to be another address:

pagedir[virt >> 22] & ~0xfff

Second part:

The result of the first part, it seems to me, returns an address, so in this second part is being indexed (pointed) another memory region from that address:

(pagedir[virt >> 22] & ~0xfff))[virt << 10 >> 10 >> 12];

The parentheses around pagedir and in the operations made with it, they mean that the resulting address of these operations will be indexed by the square brackets and within the square brackets is indexed which is equivalent to an arithmetic of pointers: (...)[virt << 10 >> 10 >> 12]

Third part:

At that time the cast of (uint32_t*) is saying that the indexed memory region (pointed out), as stated in the second part, should be treated in the base (size) of uint32_t, then, any operation (allocations, calculations, assignments, etc.) performed will be on that basis:

((uint32_t*) (pagedir[virt >> 22] & ~0xfff))[virt << 10 >> 10 >> 12];

Fourth part:

Finally, the whole operation is pointed by a guy void, because the function returns a data of this type and, in my view, this function is leaving to those who receive its return to define how it wants to store the returned value, so whoever receives this return will have to make a cast for some kind:

return (void*) ((uint32_t*) (pagedir[virt >> 22] & ~0xfff))[virt << 10 >> 10 >> 12];

I’ll leave a link for you to find more information about pointers: Programming in C/Pointers

  • Excellent answer Roger.

  • Then log in the case when I do this (uint32_t*) (pagedir[virt >> 22] & ~0xfff) are picking up the page come and turning to uint32_t and 0xfff to uint32_t also?

  • user46542 I edited my answer to get more complete. I realized there were important parts I forgot to comment on. I apologize for having forgotten. I hope I have not caused more damage to your understanding. I ask you to read the answer again and check if there are any doubts.

  • Our guy really paid off !!!

  • Roger gave me one more doubt if I put (unsigned char *) the expression will be treated as 1 byte ?

  • What will happen is that the addresses indexed by the expression (...)[virt << 10 >> 10 >> 12]" (as I explained in the second part) will point to 1 byte memory blocks. An array is nothing but a pointer, so a pointer uint32_t *var; is equivalent to an array uint32_t var[ ]. If you change the cast uint32_t* for unsigned char* the pointer will go on to point 8-bit memory blocks (1 byte).

  • Imagine that a pointer uint32_t ptrVar[ ]; is pointed to some region of memory. By uint32_t be a 32-bit type, so, ptrVar[ ]; points to a 32-bit memory block -> 01101001 00101010 00100011 00111011. When you cast a (unsigned char *) ptrVar[ ]; , ptrVar[ ]; will point to an 8-bit (1 byte) memory block, so if you point it to the same previous memory position it will point to only 8 bits (see if the platform is big endian or Litle andian) -> 00111011 (whereas the platform is Litle andian).

  • Now I understand everything

Show 3 more comments

0

The casting of a pointer to (void*) is necessary for some functions that use a "generic pointer" as an argument. A pointer, in addition to pointing out an address of a variable, also stores the size in memory that that variable occupies. When we do casting, we are changing the size of the variable the pointer stores.

  • Pointers do not keep the size of the address they point to. They have a type and each type has a size.

Browser other questions tagged

You are not signed in. Login or sign up in order to post.