I recently fixed a bug in which a __declspec(align(64))
member of a struct was misaligned because of the way the memory for the struct was allocated. So, I'm looking a way to work around such situations.
For example, consider the following struct:
struct foo {
__declspec(align(64)) int bar[BAZ_LEN];
int baz;
};
If allocated on the stack, the compiler would take care of the alignment. If allocated via malloc()
, it would not work. This will break the code that accesses bar if it depends on its alignment for performance or correctness reasons (or both).
So, the question is: what is the best way to handle such situations? In my situation struct foo
can be considered opaque for all but 'private' functions of my component.
Clarification/update. Thanks so much for the answers. I should have said this beforehand, but the problem was that the user of my struct allocated a chunk of memory and sliced it into multiple pieces, and one of the middle ones was an array of foo_t
structus. The offset to that array is not constant, so aligning the starting address is not likely to help. I'm looking for a way to allow such usage of my structs while retaining some of the alignment assumptions.
The solution I have in mind right now (have not tried this) is to add a padding member:
struct foo {
__declspec(align(64)) int bar[BAZ_LEN];
int baz;
char padding[64];
};
And than in every function do the following (wrapped in a macro):
void f(foo_t *foo_)
{
foo_t *foo = (foo_t *)(((uintptr_t)foo_ & ~63) + 64);
...
}
This wastes 64 bytes per struct which is not an issue in my case. Since the padding member is never accessed the shift would not cause any segfaults. However this solution adds quite a bit of mental overhead since the alignment has to be sanitized for each public function...
The only standard rule is that the address returned by malloc will be suitably aligned to store any kind of variable. What exactly that means is platform-specific (since alignment requirements vary from platform to platform).
malloc has no knowledge of what it is allocating for because its parameter is just total size. It just aligns to an alignment that is safe for any object.
The GNU documentation states that malloc is aligned to 16 byte multiples on 64 bit systems.
Alignment refers to the arrangement of data in memory, and specifically deals with the issue of accessing data as proper units of information from main memory. First we must conceptualize main memory as a contiguous block of consecutive memory locations. Each location contains a fixed number of bits.
In standard C11, you can use aligned_alloc()
:
ISO/IEC 9899:2011
7.22.3.1 The aligned_alloc function
Synopsis
#include <stdlib.h> void *aligned_alloc(size_t alignment, size_t size);
Description
2 Thealigned_alloc
function allocates space for an object whose alignment is specified by alignment, whose size is specified by size, and whose value is indeterminate. The value of alignment shall be a valid alignment supported by the implementation and the value of size shall be an integral multiple of alignment.Returns
3 Thealigned_alloc
function returns either a null pointer or a pointer to the allocated space.
Or you can use POSIX posix_memalign()
:
NAME
posix_memalign
— aligned memory allocation (ADVANCED REALTIME)SYNOPSIS
#include <stdlib.h> int posix_memalign(void **memptr, size_t alignment, size_t size); [Option End]
DESCRIPTION
The
posix_memalign()
function shall allocatesize
bytes aligned on a boundary specified byalignment
, and shall return a pointer to the allocated memory inmemptr
. The value ofalignment
shall be a power of two multiple of sizeof(void *).Upon successful completion, the value pointed to by
memptr
shall be a multiple of alignment.If the size of the space requested is 0, the behavior is implementation-defined; the value returned in
memptr
shall be either a null pointer or a unique pointer.The free() function shall deallocate memory that has previously been allocated by posix_memalign().
RETURN VALUE
Upon successful completion,
posix_memalign()
shall return zero; otherwise, an error number shall be returned to indicate the error.
Note that there is no aligned_realloc()
nor a POSIX equivalent.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With