7

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...

kolbusa
  • 153
  • 1
  • 7
  • Maybe _aligned_malloc can help http://msdn.microsoft.com/en-us/library/8z34s9c6.aspx – manuell Dec 31 '13 at 15:12
  • What happens if you apply the declspec to the struct, not the first member of the struct? – James Dec 31 '13 at 15:22
  • 1
    @james Not much, malloc don't know you've done that, malloc normally returns memory suitable aligned for the maximum needed by a native type, an alignment larger than that, as 64 here, would likely exceed that. – nos Dec 31 '13 at 15:36
  • @KerrekSB I would prefer sticking to c99. But, for what it's worth, our product provides memory management routines that are similar to the aligned_malloc() referenced below. The problem is that the caller allocates a chunk of memory and then slices it into multiple pieces one of which happens to be an array of my structs. The offset to my chunk is not constant, so I guess aligned_alloc() or posix_memalign() would not help here. – kolbusa Dec 31 '13 at 22:43

2 Answers2

6

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 The aligned_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 The aligned_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 allocate size bytes aligned on a boundary specified by alignment, and shall return a pointer to the allocated memory in memptr. The value of alignment 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.

Jonathan Leffler
  • 730,956
  • 141
  • 904
  • 1,278
  • We have an internal function that's similar to posix_memalign/aligned_alloc(). The problem is that the caller allocates a chunk of memory and then slices it into multiple pieces one of which happens to be an array of my structs. The offset to that piece is not constant, so I guess aligned_alloc() or posix_memalign() would not help here... – kolbusa Dec 31 '13 at 22:45
  • 1
    @kolbusaL If your memory has to be carved out of a bigger chunk, then you're definitely handicapped. You might find [What is the recommended way to align memory in C++11](http://stackoverflow.com/questions/20791428/what-is-the-recommended-way-to-align-memory-in-c11) of some relevance, and maybe [Solve the memory alignment in C interview question that stumped me](http://stackoverflow.com/questions/227897/solve-the-memory-alignment-in-c-interview-question-that-stumped-me/) too, though I get the impression you know what you need to know that's in the second one. – Jonathan Leffler Dec 31 '13 at 23:28
4

You can use posix_memalign for dynamic aligned allocation. In C11 there is a memory alignment control, e.g. "Memory Alignment Control" in this blog.

Sebastian
  • 8,046
  • 2
  • 34
  • 58