Jump to content
  • Advertisement
Sign in to follow this  
Andrew Russell

How does new handle alignment?

This topic is 4866 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Recommended Posts

OK, I'm working on some fairly low level structure (C++ struct/class) manipulation type stuff. Essentially, I'm manually alocating a structure. The idea is to replicate the behaviour of C++ itself. Now, at the moment, I'm simply doing new char[] to alocate a buffer. However I don't know what the alignment of that would be. I noticed MSVC has an aligned_malloc function (sub-question: what is the GCC equvilent?), so I was going to move over to this. It then occured to me that I should see how operator new does it. Now operator new only takes one argument (size). How you'd magically generate the information to call aligned_malloc, which takes size and alignment, I don't understand. So question is: How does C++ handle alignment? Note: I know the required alignment of my structures already.

Share this post


Link to post
Share on other sites
Advertisement
Quote:
(sub-question: what is the GCC equvilent?)


POSIX 1003.1d defines the function posix_memalign (so named because an earlier, now obsolete function memalign found on many systems). Also, all glibc malloc implementations always return 8-byte aligned addresses.

Share this post


Link to post
Share on other sites
What the standard says is:
Quote:

The pointer returned shall be suitably aligned so that it can be converted
to a pointer of any complete object type and then used to access the object or array in the storage
allocated (until the storage is explicitly deallocated by a call to a corresponding deallocation function).


basicly that means on an x86 system you could get mostly anything (though most implementations does return at least 4byte aligned addresses) and on something like 68k/PPC and other systems where odd addresses gives bus-errors for non byte types you are guaranteed to get an even address.

And that's it.

Share this post


Link to post
Share on other sites
OK, so new calls malloc (right?), which will always give an 8-byte aligned address (at least on glibc). So I could just call new char[whatever] or indeed new whatever, and the resultant pointer would be aligned to 8 bytes (nothing needs anything bigger, right?).

Basically, I just don't want to alocate something with new char[] and find that when I placement-new over the top of that, the buffer has a lower alignment that the struct I'm dropping on it.

So... is new char[] the equivelent of what C++ does anyway? Does it just always give you an 8-byte aligned pointer (effectivly making alignment a non-issue)?

And what about MSVC?

Share this post


Link to post
Share on other sites
This should answer all your questions on portable alignment: Boost::Pool on Alignment

Essentially, new is guaranteed to properly align a block of size X to hold an array of any structure of size X or smaller. Thus, allocating 10 bytes with new would be aligned to hold anything 1 to 10 bytes in size, and it could be 2 objects of size 5 or 3 objects of size 3 etc. It gets somewhat tricky when you want to put different sizes in a single block, but it is still easily doable.

Also, boost has a templated value that will return the alignment requirements of any type.

Share this post


Link to post
Share on other sites
should work with any c++ compiler:

void* AlignedMalloc(size_t size,int byteAlign)
{
void *mallocPtr = malloc(size + byteAlign + sizeof(void*));
size_t ptrInt = (size_t)mallocPtr;

ptrInt = (ptrInt + byteAlign + sizeof(void*)) / byteAlign * byteAlign;
*(((void**)ptrInt) - 1) = mallocPtr;

return (void*)ptrInt;
}

void AlignedFree(void *ptr)
{
free(*(((void**)ptr) - 1));
}


Share this post


Link to post
Share on other sites
Ah, ok, I gotcha. From the boost thing:

Quote:
Predicate 2: Any block of memory allocated as an array of characters through operator new[] (hereafter referred to as the block) is properly aligned for any object of that size or smaller


Which basically means that the memory allocation will round up to the nearest 2^N boundary when it allocates (up to 8 byte alignment?). Meaning an struct of 6 chars, which needs an alignment of 1, will just get an alignment of 8 (and bugger the wasted 2 bytes). An 8 byte alignment being suitable for 1 byte alignment data.

So I can use new char[] and safely drop anything on it, as long as it fits and it's properly aligned within itself? (I am thinking "yes")

Of course, this raises an interesting question - say my 6-char structure - if I made an array of 3 of them, would it use 18 bytes, or 24? Unless it knew that it only needs 1-byte alignment, it would have to be 24, right?

Or does that 6-byte struct get padded into 8 bytes by the compiler anyway?

Share this post


Link to post
Share on other sites
Quote:
Original post by Andrew Russell
OK, so new calls malloc (right?)


Not nessecaraly it's up to compiler vendor to-do so.

On a slightly unrelated note don't bother using new char, any form of implicit invocation of new will initialize memory, just invoke operator new & delete explicitly with the size required it will allocate a chunk of uninitialized memory e.g.:


#include <new>

void* buf = ::operator new(sizeof(foo)); // allocates only
//...
foo* f = ::new(buf) foo(/* ... */); // constructs only
//...
f->~foo(); //destructs only
//...
::operator delete(buf); // deallocates only



Another alternative is to overload operators new/delete for a whole class hierarchy then the compiler will also give you the correct size to allocate also there is a special variant signature of delete for class or class hierarchies which the last parameter gives you the size of the actual memory passed including void pointer:


struct foo {

void* operator new(std::size_t n);

//...

// compiler automatically passes the size for you implicitly.
void operator delete(void* p, std::size_t n);

Share this post


Link to post
Share on other sites
Ah great, thanks for that - I'll go with the first one in that case (implicit call to operator new). I don't have a class hirachy to put a member operator new in.

Share this post


Link to post
Share on other sites
Quote:
Original post by Andrew Russell
[...]So I can use new char[] and safely drop anything on it, as long as it fits and it's properly aligned within itself? (I am thinking "yes")
Yes

Quote:
Of course, this raises an interesting question - say my 6-char structure - if I made an array of 3 of them, would it use 18 bytes, or 24? Unless it knew that it only needs 1-byte alignment, it would have to be 24, right?

Or does that 6-byte struct get padded into 8 bytes by the compiler anyway?
The structure must be properly padded by the compiler such that putting two of them with 0 bytes between will result in both being properly aligned if the first one is.

I don't know if char[x] must be properly aligned for an x-byte structure, but using 'new char[x]' will meet that requirement.

Share this post


Link to post
Share on other sites
Sign in to follow this  

  • Advertisement
×

Important Information

By using GameDev.net, you agree to our community Guidelines, Terms of Use, and Privacy Policy.

We are the game development community.

Whether you are an indie, hobbyist, AAA developer, or just trying to learn, GameDev.net is the place for you to learn, share, and connect with the games industry. Learn more About Us or sign up!

Sign me up!