How to declare an aligned struct in C

Started by
14 comments, last by drakostar 14 years, 6 months ago
The std way I know in VC++ is like this:

 __declspec(align(X)) struct SomeStruct
{
   float a,b,c,d;
};

Where X is the desired alignment which in my case is 16. When a local variable is declared the alignment actually works with CPP, but in C it fails to align the object properly. An assertion to the allocated address always fails in C. Here is what I mean by that:

void AlignmentCheck()
{
   struct SomeStruct abc;
   assert( ( 0 == (((size_t)(&abc))&15) ) ); // this always fails
}

Some SSE operations on the struct, as expected, also fails. Am I doing something wrong here? Or do I need to work around this by allocation a large buffer and manually adjust the address to fix this problem. Isn't the compiler capable of handling that.
What if everyone had a restart button behind their head ;P
Advertisement
I have actually found a solution but I don't know why its working?
Could somebody please explain.

The solution I found is to typedef the structure. Actually I tried this before but it didn't work and that is why I am confused.

The first time I tried I did this:
[source lang='C']typedef __declspec(align(16)) struct SomeStruct SomeStruct;


But this didn't work. Then I changed the struct name for the typedef:
[source lang='C']typedef __declspec(align(16)) struct SomeStruct SomeStruct_A;


And this works i.e. when I declare a variable for SomeStruct_A it is declared aligned.
What is wrong with my first declaration (typedef)?
What if everyone had a restart button behind their head ;P
A few things -

This is compiler specific. There is nothing in the language about forcing an alignment. The libraries are required to place things in a proper alignment for the type, but it is an implementation detail.

Your cast is a bug: (((size_t)(&abc))&15)
The result of the & operator is a pointer of the same type as abc. A size_t object is not the same as a pointer.

For the stack, Microsoft's compiler defaults to 4-byte alignment on the x86 platform, unless you tell it otherwise.

If you are going to be using variables for SSE, you should be using the intrinsic types. For example the types __m128i __m128d, __m64 are all properly aligned for use in MMX/SSE/SSE2 instructions.
Quote:
A few things -

This is compiler specific. There is nothing in the language about forcing an alignment. The libraries are required to place things in a proper alignment for the type, but it is an implementation detail.

Your cast is a bug: (((size_t)(&abc))&15)
The result of the & operator is a pointer of the same type as abc. A size_t object is not the same as a pointer.

For the stack, Microsoft's compiler defaults to 4-byte alignment on the x86 platform, unless you tell it otherwise.

If you are going to be using variables for SSE, you should be using the intrinsic types. For example the types __m128i __m128d, __m64 are all properly aligned for use in MMX/SSE/SSE2 instructions.

Actually there is something which you called 'forcing alignment'. Basically what you do is take a large enough buffer and adjust the address so that it starts at an appropriate boundary. This can be manually done. Let me show you how:

float buff[4 + 3];
SomeStruct* ptr = (SomeStruct*)(( buff + 15 ) & ~15 );

This will adjust the address of the buff, such that it starts at right boundary.

And about that cast. I assumed sizeof(size_t)==sizeof(void*).

[edit]
And I cant really use __m128 because my whole point in using these structures to allow a fallback mechanism in case SSE is not supported by an architecture.
What if everyone had a restart button behind their head ;P
Quote:Original post by obhi
typedef __declspec(align(16)) struct SomeStruct SomeStruct;
At first I was surprised that this even compiles, but I can see why.

It would introduce a synonym to a type. The synonym would be checked in the symbol table. It already appears and it is an exact match as far as the compatible type comparisons are concerned, so the compiler is free to discard the second duplicate definition.
Quote:Original post by obhi

failed
typedef __declspec(align(16)) struct SomeStruct SomeStruct;

succeeded
typedef __declspec(align(16)) struct SomeStruct SomeStruct_A;

And this works i.e. when I declare a variable for SomeStruct_A it is declared aligned. What is wrong with my first declaration (typedef)?


C compilers don't handle aliases as well as C++ compilers. Maybe there's something in the spec about it. A typical approach is to prepend or append characters to the struct name not the alias.

typedef __declspec(align(16)) struct SomeStruct_A SomeStruct;

- unless you want the alias to indicate the alignment.

Also

__declspec(align(16))

is this particular to the compiler your using? Is that a microsoft directive?

Other compilers using special includes or #pragma directives for alignment.

#pragma pack(push,1)

typedef struct tagSomeStruct {
// struct members
} SomeStruct, *PSomeStruct;

#pragma pack(pop);

Check yer docs

"I thought what I'd do was, I'd pretend I was one of those deaf-mutes." - the Laughing Man
Quote:Original post by obhi
And I cant really use __m128 because my whole point in using these structures to allow a fallback mechanism in case SSE is not supported by an architecture.
SSE was introduced in the Pentium III, nearly 11 years ago.

The fastest Pentium II processors were 450 MHz. Are you honestly going to build your game with support for that kind of processor?
Yea, I guess you are right frob.
And yes that's a Microsoft directive. That is why I mentioned Microsoft Visual C++ compiler at the beginning.
Thanks for your support. I have a working solution now, though not a satisfactory one :(
What if everyone had a restart button behind their head ;P
Quote:Original post by frob
Quote:Original post by obhi
And I cant really use __m128 because my whole point in using these structures to allow a fallback mechanism in case SSE is not supported by an architecture.
SSE was introduced in the Pentium III, nearly 11 years ago.

The fastest Pentium II processors were 450 MHz. Are you honestly going to build your game with support for that kind of processor?


No, I am using SSE2,SSE3 for that matter. My computer is an old one which does not support SSE4. No GPU for physics either :(. And I am working on a physics engine.
Anyway what do you suggest?
What if everyone had a restart button behind their head ;P
Quote:Original post by LessBread
C compilers don't handle aliases as well as C++ compilers. Maybe there's something in the spec about it. A typical approach is to prepend or append characters to the struct name not the alias.
I don't have anything from the C spec, but the GCC doumentation explicitly states that:
You cannot specify alignment for a typedef name because such a name is just an alias, not a distinct type.

Quote:Other compilers using special includes or #pragma directives for alignment.

#pragma pack(push,1)

typedef struct tagSomeStruct {
// struct members
} SomeStruct, *PSomeStruct;

#pragma pack(pop);

Check yer docs
The modern GCC syntax would be __attribute__ ((aligned (1))), and or __attribute__((packed)). See the relevant docs for details.

Tristam MacDonald. Ex-BigTech Software Engineer. Future farmer. [https://trist.am]

This topic is closed to new replies.

Advertisement