Day 346 - Type casting in PLATFORM_DEALLOCATE_MEMORY

Hi,

In Day 346 around the 29:00 mark, Casey writes this line in PLATFORM_DEALLOCATE_MEMORY, casting a platform_memory_block pointer to a win32_memory_block pointer to deallocate it:

1
2
3
4
5
6
#define PLATFORM_DEALLOCATE_MEMORY(name) void name(platform_memory_block *Block)
typedef PLATFORM_DEALLOCATE_MEMORY(platform_deallocate_memory);

...

win32_memory_block *Win32Block = ((win32_memory_block *)Block);


The relevant structs are defined as below:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
struct platform_memory_block
{
    u64 Flags;
    u64 Size;
    u8 *Base;
    umm Used;
    platform_memory_block *ArenaPrev;
};

struct win32_memory_block
{
    platform_memory_block Block;
    win32_memory_block *Next;
    win32_memory_block *Prev;
    u64 LoopingFlags;
};


I think I understand how pseudo-polymorphism in C works, making use of the fact that the pointer to a struct is also a pointer to the first element in that struct, and if that element is also struct, then also a pointer to the first element in that struct and so on. Casey mentions this as well when he rearranges the win32_memory_block struct like the above configuration.

But I don't understand how the actual code he wrote is an example of this? The platform_memory_block struct does not have any knowledge of the win32_memory_block, so why does this code work?

I guess I am missing something obvious -- what is it?

Edited by idc112 on
The Block parameter is a pointer to a memory location where a platform_memory_block type exists, but the memory initialized at that location is actually a win32_memory_block.

Which is fine because platform_memory_block is the type of the first member of win32_memory_block, and so it is the first thing at that location, so you can cast freely between the two types.

This is basically the same as using inheritance.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
struct platform_memory_block
{
    u64 Flags;
    u64 Size;
    u8 *Base;
    umm Used;
    platform_memory_block *ArenaPrev;
};

struct win32_memory_block : platform_memory_block
{
    //platform_memory_block Block;
    win32_memory_block *Next;
    win32_memory_block *Prev;
    u64 LoopingFlags;
};
William,

You're right, I guess I was a victim of coding along without pausing to understand what was really going on with the allocations in the first place. I did in fact overlook that the original allocations were win32_memory_blocks, that platform_memory_blocks were never allocated by themselves. Overnight sleep and your explanation makes it clear. :-)

Thanks!

Edited by idc112 on