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.
– Jorge B.
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
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.
– Roger
Our guy really paid off !!!
– user46542
Roger gave me one more doubt if I put (unsigned char *) the expression will be treated as 1 byte ?
– user46542
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 pointeruint32_t *var;
is equivalent to an arrayuint32_t var[ ]
. If you change the castuint32_t*
forunsigned char*
the pointer will go on to point 8-bit memory blocks (1 byte).– Roger
Imagine that a pointer
uint32_t ptrVar[ ];
is pointed to some region of memory. Byuint32_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).– Roger
Now I understand everything
– user46542