by Digby » Jul 29, 2001 @ 4:47pm
Jacco,<br><br>I've never seen the PQ source, but from the code Dan posted I don't understand the benefit of that scheme either. He's just making sure that each allocated chunk is an even multiple of 16 bytes.<br><br>The issue I was referring to in my comments was that some CPUs require you to access data types on a sizeof(data type) byte aligned boundary. I don't understand how Dan's code guarantees that will happen.<br><br>The way I handle memory alignment issues is to write a wrapper around malloc that allocates additional bytes to every request and then slide the starting address returned by malloc up a bit until it is on the alignment boundary. I then store the original address returned by malloc in the 4 bytes immediately before the newly aligned address. The free routine then has to back up 4 bytes, dereference this address to get the stored actual block address, and then pass that to free().<br><br>For larger buffers (for .wav, .bmp, or surface data) I just use VirtualAlloc. It only allows you to allocate with a 4K granularity, but the addresses are guaranteed to be aligned on 4K byte boundaries. Also, when you use VirtualAlloc it is very fast (no heap walking looking for free blocks) and will never cause heap fragmentation.<br><br>Here's some code that does the memory allocation on n-byte boundaries. Just change the constant, c_ulAlign, to whatever you want.<br><br>const unsigned long c_ulAlign = 16;<br>const unsigned long c_ulAlignExtra = (c_ulAlign - 1) + sizeof(void*);<br><br>void * malloc_align (size_t size)<br>{<br>unsigned long ulBaseAddr;<br>unsigned long ulRetAddr;<br><br> ulBaseAddr = (unsigned long)malloc(size + c_ulAlignExtra);<br> ulRetAddr = (ulBaseAddr + c_ulAlignExtra) & ~(c_ulAlign - 1);<br> *(void**)(ulRetAddr - sizeof(void*)) = (void*)ulBaseAddr;<br> <br> return((void*)ulRetAddr);<br>}<br><br>void free_align (void* pv)<br>{<br> free(*(void**)((unsigned long)pv - sizeof(void*)));<br>}<br><br><br><br>