🎉 Celebrating 25 Years of GameDev.net! 🎉

Not many can claim 25 years on the Internet! Join us in celebrating this milestone. Learn more about our history, and thank you for being a part of our community!

What is the meaning of "alignment-1" in the "C++: custom memory allocation" article?

Started by
4 comments, last by mychii 2 years, 3 months ago

In this article https://www.gamedev.net/tutorials/programming/general-and-gameplay-programming/c-custom-memory-allocation-r3010/​ it says “To n-byte align a memory address x we need to mask off the log2(n) least significant bits from x. Simply masking off bits will return the first n-byte aligned address before x, so in order to find the first after x we just need to add alignment-1 to x and mask that address.” in the Aligned Allocations implementation section, and codes that use alignment - 1.

I generally understand of what this article offers, but what's been bugging me is I can't quite understand just this particular part about “alignment - 1”. What is the reason of subtracting alignment by 1 here?

edit: sorry maybe this should've been in Beginner's channel

Advertisement

This is just the standard way of aligning stuff in memory. In general some data needs to be aligned on a particular boundary. For instance if something is 16 byte aligned it would have to start on address 0 or 16 or 32 or 48 and so forth. Now let's say for some reason you are sitting at address 19 and you want to put something in the next available memory which would be 32 in the the case of 16 byte aligned memory. You add 15 (i.e. 16-1), so that brings you to 34. Then you divide by 16 which gets you to 2 (for integer division) and multiply back by 16 which brings you to 32. Note if you had added 16 instead of 15 you would waste memory because if you had started at exactly byte 16 you would already be aligned. Hence you subtract 1.

This works for any alignment but for computers you typically want to align by powers of 2 so instead of doing the multiply divide, you can simply shift right 4 bits and then left 4 bits, which clears the lower four bits and does the same thing. Alternatively you can simply mask off the lower four bits which does the exact same thing again, which is what they are talking about here.

Thanks a bunch, I think it makes sense to me now. I drop some examples to verify my understanding of your post in case I'm wrong.

Understanding the meaning of the (alignment - 1), using divide/multiply method:
Example 1
address to align: 16
alignment: 16 bytes

without alignment - 1 (16):
16 + 16 = 32
32 / 16 = 2
2 * 16 = 32 <-- ends up at address 32

with alignment - 1 (16 - 1 = 15):
16 + 15 = 31
31 / 16 = 1 (integer division)
1 * 16 = 16 <-- ends up at address 16 instead of 32, which saves 16 bytes

Example 2
address to align: 16
alignment: 8 bytes

without alignment - 1 (8):
16 + 8 = 24
24 / 8 = 3
3 * 8 = 24 <-- ends up at address 24

with alignment - 1 (8 - 1 = 7):
16 + 7 = 23
23 / 8 = 2 (integer division)
2 * 8 = 16 <-- ends up at address 16 instead of 24, which saves 8 bytes

Understanding n-byte alignment of an address to the log2(n) lower bits of that address using bit shifting and masking methods, with that (alignment - 1):
Example 3
address to align: 19

16-byte alignment:

1.  address + (alignment - 1): 19 + (16 - 1) = 33 (0010 0001)
2a. bit shifting
    shift right 4 bits: 0000 0010
    then shift left 4 bits: 0010 0000 <-- ends up at address 32
2b. masking
    33 & ~(16 - 1)
    0010 0001 & ~(0000 1111)
    0010 0001 & 1111 0000 = 0010 0000 <-- ends up at address 32

8-byte alignment:

1.  19 + (8 - 1) = 26 (0001 1010)
2a. bit shifting
    shift right 3 bits: 0000 0011
    then shift left 3 bits: 0001 1000 <-- ends up at address 24
2b. masking
    26 & ~(8 - 1)
    0001 1010 & ~(0000 0111)
    0001 1010 & 1111 1000 = 0001 1000 <-- ends up at address 24

I hope I got this!

mychii said:

2b. masking
    33 & ~(16 - 1)
    0010 0010 & ~(0000 1111)
    0010 0010 & 1111 0000 = 0010 0000 <-- ends up at address 32

I hope I got this!

Yeah I think you pretty much got it. You made a slight error in the part I quoted above. The binary 0010 0010 is actually 34 not 33. However I imagine that's just a typo.

You're right, fixed! Thanks again.

This topic is closed to new replies.

Advertisement