Struct alignment (VC2005)

Started by
6 comments, last by Wolfdog 16 years, 6 months ago
Hi all, hopefully a simple question: How do you align structs in VC2005? I'm trying to align my matrix class to a 16-byte boundary. My matrix class is defined as:

#pragma warning(disable:4324) // 'Foo' : structure was padded due to __declspec(align())
__declspec(align(16)) class EMatrix
{
   // ...
};

And I have an EMatrix as a member of my model class:

class EModel : public ESceneObject
{
   // ...

protected:
   EID m_id;
   EVector3 m_vBoundingBoxMin;
   EVector3 m_vBoundingBoxMax;

   EMatrix m_matTransform;

   // ...

However, when I come to use the model's transform matrix, it's address is 0x011ea468, which obviously isn't 16 byte aligned. The D3DX version, D3DXMATRIXA16 uses the __declspec(align) modifier every time a matrix is defined: typedef __declspec(align(16)) _D3DXMATRIXA16 D3DXMATRIXA16, *LPD3DXMATRIXA16; Is there any way to avoid doing that? It just seems a bit odd that I have to mark the matrix as 16-byte aligned in the class header, and also wherever it's used. And what does marking the class as aligned in the class header do? The MSDN says "This type now has a 32-byte alignment attribute, meaning that all instances must start on a 32-byte boundary." (align(32) in their example). That's clearly not the case here. Cheers, Steve
Advertisement
Ok, it looks like it's because my EModel class instance is allocated with operator new. Is there any way to gat around this? The EMatrix class instance is a member of the EModel class, and the EModel class is allocated on the heap.

This is looking like there's no way around it...
Can you not override new for that particular class/struct?
I can't overload new for EMatrix, because that'll only have an effect if I create the matric on its own and not if it's a member of another class.
I don't really want to overload new for my EModel class, because then I have to do that for every class that contains a matrix, which is exactly what I want to avoid.
Works fine in this little test app. Both Matrices were aligned. I set the alignment in the vcproject file to be 4 and 8 and it made no diff

__declspec(align(16)) class Matrix{   long l1;   long l2;   long l3;   long l4;};__declspec(align(4)) class Number{   long l1;};#include <iostream>using namespace std;int main(int argc, char** argv){  Matrix oMatrix1;  Number oNumber1;  Matrix oMatrix2;  Number oNumber2;  cout << "Matrix 1: " << hex << &oMatrix1 << endl;  cout << "Number 1: " << hex << &oNumber1 << endl;  cout << "Matrix 2: " << hex << &oMatrix2 << endl;  cout << "Number 2: " << hex << &oNumber2 << endl;  unsigned char ucTemp;  cin >> ucTemp;  return 0;}


Edit however

__declspec(align(16)) class Matrix{   long l1;   long l2;   long l3;   long l4;};__declspec(align(4)) class Number{   long l1;};#include <iostream>using namespace std;int main(int argc, char** argv){  Matrix oMatrix1;  Number oNumber1;  Matrix oMatrix2;  Number oNumber2;  cout << "Matrix 1: " << hex << &oMatrix1 << endl;  cout << "Number 1: " << hex << &oNumber1 << endl;  cout << "Matrix 2: " << hex << &oMatrix2 << endl;  cout << "Number 2: " << hex << &oNumber2 << endl;  Matrix* pMatrix1 = new Matrix();  Number* pNumber1 = new Number();  Matrix* pMatrix2 = new Matrix();  Number* pNumber2 = new Number();  cout << "Matrix 1: " << hex << pMatrix1 << endl;  cout << "Number 1: " << hex << pNumber1 << endl;  cout << "Matrix 2: " << hex << pMatrix2 << endl;  cout << "Number 2: " << hex << pNumber2 << endl;  unsigned char ucTemp;  cin >> ucTemp;  return 0;}

new aligned everything to 8 per vcproj settings
Use _aligned_malloc() and _aligned_free() instead of new/delete.
For example,
Matrix* pMatrix = (Matrix*)_aligned_malloc(sizeof(Matrix), 16);
...
_aligned_free(pMatrix)
Again, that means I need to allocate the matrix seperately from the class, with an aligned operator new or malloc :(
In Windows (I am unsure of other platforms) New will always align only on a boundry of the largest type, ie 8 bytes for 32 bit platforms, no matter what you do to it. It all falls down to the win32 HeapAlloc function, so you can use malloc with placment new -- I think thats what it is called -- example:
void *pointer = malloc(sizeof(EMatrix)+16);EMatrix *matrix = new((pointer+16)&(~15)) EMatrix;// Should most likely only free pointermatrix->~EMatrix();free(pointer);


I also can't recall what it is named but there is a version of malloc that will align for you, but it does this exact same thing inside. -- EDIT: _aligned_malloc() thats what it was songho reminded me.

Of course you could do the same thing with just allocating two EMatrix classes with new and move the pointer the same way, although that will really F your destruction, etc, So i recommend against it.

Anycase sorry for the bad news that alignment stuff is so missleading in the documentation. It only guarantees that the structure will align to 16 bytes within the class, so once you throw new at it everything is out the window.

[Edited by - Wolfdog on September 18, 2007 10:23:20 AM]

This topic is closed to new replies.

Advertisement