Jump to content
  • Advertisement
Sign in to follow this  
obhi

How to declare an aligned struct in C

This topic is 3266 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

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.

Share this post


Link to post
Share on other sites
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)?

Share this post


Link to post
Share on other sites
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.

Share this post


Link to post
Share on other sites
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.

Share this post


Link to post
Share on other sites
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.

Share this post


Link to post
Share on other sites
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

Share this post


Link to post
Share on other sites
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?

Share this post


Link to post
Share on other sites
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 :(

Share this post


Link to post
Share on other sites
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?

Share this post


Link to post
Share on other sites
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.

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!