S
Stephen Horne
I understand that the next C++ standard will have features to handle
the alignment of data types. This is good, but a bit late for me!
I've been using some template trickery to handle alignment issues for
some time. What I usually want is a type that takes the same amount of
space and has the same alignment as some other type, but which doesn't
have constructors, destructors etc. The idea is that initialisation
and cleanup can be done with casts, placement new and explicit
destructor calls, but that this memory-only type can live in a union
or whatever.
To get the alignment of an existing type, I use something like...
template<typename T>
class CAlign_Of
{
private:
struct CDummy
{
char m_Char;
T m_T;
};
public:
enum { Align = ((size_t) &(((CDummy*) 0)->m_T)) };
};
Which I figure should be portable to any platform where char is a
single byte (though I don't think even that is guaranteed).
To create the replacement type, however, is a bit more of a problem.
To create a type the right size, you just use a template struct
containing and array of chars, but getting the alignment right is the
problem.
Using template specialisation to present a range of options isn't too
problematic, but how to code the options.
At the moment I have a #ifdef conditional compilation solution. The
Microsoft VC++ block uses the __declspec(align(n)) non-portable
solution, which annoyingly only accepts literal integers (as opposed
to compile-time constants) for the parameter. But for other compilers,
all I can come up with is the following...
template<size_t S>
struct CSpace_For<S, 1> { UInt8 m [ S ]; };
template<size_t S>
struct CSpace_For<S, 2> { UInt16 m [(S+1)/2]; };
template<size_t S>
struct CSpace_For<S, 4> { UInt32 m [(S+3)/4]; };
template<size_t S>
struct CSpace_For<S, 8> { UInt64 m [(S+7)/8]; };
However, there is no guarantee that any compiler will use the needed
alignment for these types. It can depend on the platform, the
compiler, and compiler settings.
Up until now, I haven't worried because I always knew what compiler I
was targetting. Now I have a problem - I'm writing a code generator
that needs to generate variant-record-like types. Those variants will
have members with types defined outside the generated code, which may
not be considered aggregates. The whole point of this project is to
sell it to unsuspecting victims, and I'd like to minimise the victim
aspect.
From what I've seen in other code generators, the usual practice is to
assume a pessimistic alignment, allocate a bit of extra memory, and do
an align-to-boundary calculation manually such as...
(address + 15) & ~15
This worries me because pessimistic may not be pessimistic enough as
extra hardward features are added that I'm not aware of - I undestand
that SIMD instructuctions require aligned data, for example, with
potentially larger alignments than 8 bytes (16 bytes certainly) - and
who knows what the next 5 years will bring.
So...
1. Is there a good portable solution now?
2. What will the standard C++ solution be?
3. How consistent are compilers in their non-standard alignment
handling right now? - e.g. does GCC c++ support an __alignof
extension similar to that on MS VC++?
the alignment of data types. This is good, but a bit late for me!
I've been using some template trickery to handle alignment issues for
some time. What I usually want is a type that takes the same amount of
space and has the same alignment as some other type, but which doesn't
have constructors, destructors etc. The idea is that initialisation
and cleanup can be done with casts, placement new and explicit
destructor calls, but that this memory-only type can live in a union
or whatever.
To get the alignment of an existing type, I use something like...
template<typename T>
class CAlign_Of
{
private:
struct CDummy
{
char m_Char;
T m_T;
};
public:
enum { Align = ((size_t) &(((CDummy*) 0)->m_T)) };
};
Which I figure should be portable to any platform where char is a
single byte (though I don't think even that is guaranteed).
To create the replacement type, however, is a bit more of a problem.
To create a type the right size, you just use a template struct
containing and array of chars, but getting the alignment right is the
problem.
Using template specialisation to present a range of options isn't too
problematic, but how to code the options.
At the moment I have a #ifdef conditional compilation solution. The
Microsoft VC++ block uses the __declspec(align(n)) non-portable
solution, which annoyingly only accepts literal integers (as opposed
to compile-time constants) for the parameter. But for other compilers,
all I can come up with is the following...
template<size_t S>
struct CSpace_For<S, 1> { UInt8 m [ S ]; };
template<size_t S>
struct CSpace_For<S, 2> { UInt16 m [(S+1)/2]; };
template<size_t S>
struct CSpace_For<S, 4> { UInt32 m [(S+3)/4]; };
template<size_t S>
struct CSpace_For<S, 8> { UInt64 m [(S+7)/8]; };
However, there is no guarantee that any compiler will use the needed
alignment for these types. It can depend on the platform, the
compiler, and compiler settings.
Up until now, I haven't worried because I always knew what compiler I
was targetting. Now I have a problem - I'm writing a code generator
that needs to generate variant-record-like types. Those variants will
have members with types defined outside the generated code, which may
not be considered aggregates. The whole point of this project is to
sell it to unsuspecting victims, and I'd like to minimise the victim
aspect.
From what I've seen in other code generators, the usual practice is to
assume a pessimistic alignment, allocate a bit of extra memory, and do
an align-to-boundary calculation manually such as...
(address + 15) & ~15
This worries me because pessimistic may not be pessimistic enough as
extra hardward features are added that I'm not aware of - I undestand
that SIMD instructuctions require aligned data, for example, with
potentially larger alignments than 8 bytes (16 bytes certainly) - and
who knows what the next 5 years will bring.
So...
1. Is there a good portable solution now?
2. What will the standard C++ solution be?
3. How consistent are compilers in their non-standard alignment
handling right now? - e.g. does GCC c++ support an __alignof
extension similar to that on MS VC++?