alignment issues

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++?
 
S

Stephen Horne

On Wed, 24 Sep 2008 07:13:31 +0100, Stephen Horne

Spot the stupid mistake...
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]; };

Should be...

template<size_t S>
struct CSpace_For<S, 2> { UInt16 m [(S+1) & ~1]; };

etc
 
J

James Kanze

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).

It is. By definition, char is a byte, and all other types
consist of an integral number of bytes.
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.

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++?

Technically, I don't think that there is a solution 100%
guaranteed by the standard. Practically, I use the following:

namespace GlobalPrivate {

template< typename T, bool isSmaller >
struct AlignTypeDetail ;

template< typename T >
struct AlignTypeDetail< T, false >
{
typedef T type ;
} ;

template< typename T >
struct AlignTypeDetail< T, true >
{
typedef char type ;
} ;

template< typename T, typename U >
struct AlignType
{
typedef typename AlignTypeDetail< U, (sizeof( T ) <
sizeof( U )) >::type
type ;
} ;
}

template< typename T >
union MaxAlignFor
{
typename GlobalPrivate::AlignType< T, char >::type c ;
typename GlobalPrivate::AlignType< T, short >::type s ;
typename GlobalPrivate::AlignType< T, int >::type i ;
typename GlobalPrivate::AlignType< T, long >::type l ;
typename GlobalPrivate::AlignType< T, long long >::type ll ;
typename GlobalPrivate::AlignType< T, float >::type f ;
typename GlobalPrivate::AlignType< T, double >::type d ;
typename GlobalPrivate::AlignType< T, long double >::type ld ;
typename GlobalPrivate::AlignType< T, void* >::type pc ;
typename GlobalPrivate::AlignType< T, MaxAlign* >::type ps ;
typename GlobalPrivate::AlignType< T, void (*)() >::type pf ;
} ;

and then declare a union:

union
{
MaxAlignFor< T > dummyForAlignment ;
unsigned char data[ sizeof( T ) ] ;
} ;

This supposes that 1) the required alignment will not be more
than the alignment of one of the types in my MaxAlignFor union,
and 2) it will not be more than the size of the type. The
latter is more or less guaranteed by the standard (albeit very
indirectly); the former seems safe for now, and if it does cause
problems in the future, it shouldn't be any real problem to add
another type to the MaxAlignFor union. (All such types must be
POD, but I can't imagine that being a problem.)
 
M

ma740988

I understand that the next C++ standard will have features to
handle thealignmentof data types. This is good, but a bit
late for me!
I've been using some template trickery to handlealignment
issues for some time. What I usually want is a type that takes
the same amount of space and has the samealignmentas 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 thealignmentof an existing type, I use something
like...
template<typename T>
class CAlign_Of
{
  private:
    struct CDummy
    {
     charm_Char;
      T    m_T;
    };
  public:
    enum { Align = ((size_t) &(((CDummy*) 0)->m_T)) };
};
Which I figure should be portable to any platform wherechar
is a single byte (though I don't think even that is
guaranteed).

It is.  By definition,charis a byte, and all other types
consist of an integral number of bytes.
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
alignmentright is the problem.
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-standardalignment
    handling right now? - e.g. does GCC c++ support an __alignof
    extension similar to that on MS VC++?

Technically, I don't think that there is a solution 100%
guaranteed by the standard.  Practically, I use the following:

    namespace GlobalPrivate {

    template< typename T, bool isSmaller >
    struct AlignTypeDetail ;

    template< typename T >
    struct AlignTypeDetail< T, false >
    {
        typedef T type ;
    } ;

    template< typename T >
    struct AlignTypeDetail< T, true >
    {
        typedefchartype ;
    } ;

    template< typename T, typename U >
    struct AlignType
    {
        typedef typename AlignTypeDetail< U, (sizeof( T ) <
sizeof( U )) >::type
                            type ;
    } ;
    }

    template< typename T >
    union MaxAlignFor
    {
        typename GlobalPrivate::AlignType< T,char>::type        c ;
        typename GlobalPrivate::AlignType< T, short >::type       s ;
        typename GlobalPrivate::AlignType< T, int >::type         i ;
        typename GlobalPrivate::AlignType< T, long >::type        l ;
        typename GlobalPrivate::AlignType< T, long long >::type   ll ;
        typename GlobalPrivate::AlignType< T, float >::type       f ;
        typename GlobalPrivate::AlignType< T,double>::type      d ;
        typename GlobalPrivate::AlignType< T, longdouble>::type ld ;
        typename GlobalPrivate::AlignType< T, void* >::type       pc ;
        typename GlobalPrivate::AlignType< T, MaxAlign* >::type   ps ;
        typename GlobalPrivate::AlignType< T, void (*)() >::type  pf ;
    } ;

and then declare a union:

    union
    {
        MaxAlignFor< T > dummyForAlignment ;
        unsignedchar   data[ sizeof( T ) ] ;
    } ;

Pretty nifty solution here. When I try to compile this though I get
the errors:

1>c:\msvc_2007-orcas\dev\test\main.cpp(52) : error C2065: 'T' :
undeclared identifier
1>c:\msvc_2007-orcas\test\main.cpp(52) : error C2621: member '<unnamed-
tag>::dummyForAlignment' of union '<unnamed-tag>' has copy constructor
1>c:\msvc_2007-orcas\test\main.cpp(53) : error C2065: 'T' : undeclared
identifier
1>c:\msvc_2007-orcas\test\main.cpp(53) : error C2070: ''unknown-
type'': illegal sizeof operand
1>c:\msvc_2007-orcas\test\main.cpp(53) : warning C4200: nonstandard
extension used : zero-sized array in struct/union

where line 52 is the line 'MaxAlignFor< T > dummyForAlignment '. What
am I doing wrong?
Thanks
 
J

James Kanze

[...]
Technically, I don't think that there is a solution 100%
guaranteed by the standard. Practically, I use the following:
namespace GlobalPrivate {
template< typename T, bool isSmaller >
struct AlignTypeDetail ;
template< typename T >
struct AlignTypeDetail< T, false >
{
typedef T type ;
} ;
template< typename T >
struct AlignTypeDetail< T, true >
{
typedefchartype ;
} ;
template< typename T, typename U >
struct AlignType
{
typedef typename AlignTypeDetail< U, (sizeof( T ) <
sizeof( U )) >::type
type ;
} ;
}
template< typename T >
union MaxAlignFor
{
typename GlobalPrivate::AlignType< T,char>::type c ;
typename GlobalPrivate::AlignType< T, short >::type s ;
typename GlobalPrivate::AlignType< T, int >::type i ;
typename GlobalPrivate::AlignType< T, long >::type l ;
typename GlobalPrivate::AlignType< T, long long >::type ll ;
typename GlobalPrivate::AlignType< T, float >::type f ;
typename GlobalPrivate::AlignType< T,double>::type d ;
typename GlobalPrivate::AlignType< T, longdouble>::type ld ;
typename GlobalPrivate::AlignType< T, void* >::type pc ;
typename GlobalPrivate::AlignType< T, MaxAlign* >::type ps ;
typename GlobalPrivate::AlignType< T, void (*)() >::type pf ;
} ;
and then declare a union:
union
{
MaxAlignFor< T > dummyForAlignment ;
unsignedchar data[ sizeof( T ) ] ;
} ;
Pretty nifty solution here. When I try to compile this though
I get the errors:
1>c:\msvc_2007-orcas\dev\test\main.cpp(52) : error C2065: 'T' :
undeclared identifier
1>c:\msvc_2007-orcas\test\main.cpp(52) : error C2621: member '<unnamed-
tag>::dummyForAlignment' of union '<unnamed-tag>' has copy constructor
1>c:\msvc_2007-orcas\test\main.cpp(53) : error C2065: 'T' : undeclared
identifier
1>c:\msvc_2007-orcas\test\main.cpp(53) : error C2070: ''unknown-
type'': illegal sizeof operand
1>c:\msvc_2007-orcas\test\main.cpp(53) : warning C4200: nonstandard
extension used : zero-sized array in struct/union
where line 52 is the line 'MaxAlignFor< T > dummyForAlignment
'. What am I doing wrong?

What is T in the union? The error messages say you haven't
defined it. There is a requirement here (although I didn't
mention it) that the instantiation argument be a complete type;
something like:

class MyClass ;
union
{
MaxAlignFor< MyClass > dummyForAlignment ;
unsigned char data[ sizeof( MyClass ) ] ;
} ;

doesn't work.

(The code above is copy/pasted from my actual headers, with the
union copy/pasted from my current implementation of Fallible,
and I compile it with g++, Sun CC and VC++ without problems.)
 
C

Chris M. Thomasson

ma740988 said:
I understand that the next C++ standard will have features to
handle thealignmentof data types. This is good, but a bit
late for me!
[...]

Pretty nifty solution here.

[...]

Check this NASTY hack out:

http://groups.google.com/group/comp.lang.c/msg/be7e0d0e97c5e1d9

use the offsetof macro to attempt to determine max alignment. Here is a
pre-alpha fairly crude C++ non-blocking region allocator which uses the
hack:

http://webpages.charter.net/appcore/vzoom/malloc/sergey_vzmem_thread.html

here is some more context:

http://groups.google.com/group/comp.programming.threads/browse_frm/thread/4038a7a8a4f5a7cb
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,744
Messages
2,569,483
Members
44,903
Latest member
orderPeak8CBDGummies

Latest Threads

Top