One of the solutions which often turns up in several posts on how to determine if a void *
points to aligned memory involves casting the void pointer. That is say I get a void *ptr = CreateMemory()
and now I want to check if memory pointed to by ptr
is a multiple of some value, say 16.
See How to determine if memory is aligned? which makes a specific claim.
A pointer p is aligned on a 16-byte boundary iff ((unsigned long)p & 15) == 0.
A solution in a similar vein appears in this post. How to check if a pointer points to a properly aligned memory location?
Can someone clarify, how does this casting work? I mean, if I had a void *ptr = CreateMem();
, it seems to me that (unsigned long)(ptr)
would give me the pointer itself reinterpreted as an unsigned long
. Why would the value of this reinterpreted void pointer have any bearing on the alignment of the memory pointed to?
EDIT: Thanks for all the useful comments. Please bear with me a bit more. Perhaps a simplified example will help me understand this better.
#include <iostream>
using namespace std;
struct __attribute__((aligned(16))) Data0 {
uint8_t a;
};
struct Data1 {
uint8_t a;
};
int main() {
std::cout<<sizeof(Data0) << "\n"; //< --(1)
std::cout<<sizeof(Data1) << "\n";
Data0 ptr0[10];
Data1 ptr1[10];
std::cout<<(unsigned long) (ptr0 + 1) - (unsigned long) ptr0 << "\n"; //< --- (2)
std::cout<<(unsigned long) (ptr1 + 1) - (unsigned long) ptr1 << "\n";
return 0;
}
To date, I always interpreted aligned memory to have the following two requirements. sizeof()
should return a multiple of the the specified size (See condition (1)). And the while incrementing a pointer to aligned struct array, the stride would end up also being a multiple of the specified size (See condition (2)).
So I am somewhat surprised to see there is a third requirement on the actual value of ptr0
as well. Or I might have misunderstood this entirely. Would the memory pointed to by ptr0
in the above example be considered aligned and not so for ptr1
?
As I am typing this, I realize I do not actually understand what aligned memory itself means. Since I have mostly dealt with this while allocating cuda buffers, I tend to relate it to some sort of padding required for my data structs.
Consider a second example. That of aligned_alloc
. https://en.cppreference.com/w/c/memory/aligned_alloc
Allocate size bytes of uninitialized storage whose alignment is specified by alignment.
I am not sure how to interpret this. Say, I do a void *p0 = aligned_alloc(16, 16 * 2)
, what is different about the memory pointed to by p0
as compared to say p1
where std::vector<char> buffer(32); char *p1 = buffer.data()
.