alignment issues

Collapse
This topic is closed.
X
X
 
  • Time
  • Show
Clear All
new posts
  • Stephen Horne

    alignment issues

    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<typena me 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(alig n(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++?

  • Stephen Horne

    #2
    Re: alignment issues

    On Wed, 24 Sep 2008 07:13:31 +0100, Stephen Horne
    <sh006d3592@blu eyonder.co.ukwr ote:

    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

    Comment

    • James Kanze

      #3
      Re: alignment issues

      On Sep 24, 8:13 am, Stephen Horne <sh006d3...@blu eyonder.co.ukwr ote:
      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<typena me 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.
      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++?
      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 dummyForAlignme nt ;
      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.)

      --
      James Kanze (GABI Software) email:james.kan ze@gmail.com
      Conseils en informatique orientée objet/
      Beratung in objektorientier ter Datenverarbeitu ng
      9 place Sémard, 78210 St.-Cyr-l'École, France, +33 (0)1 30 23 00 34

      Comment

      • Stephen Horne

        #4
        Re: alignment issues


        I already posted one thankyou, but it didn't appear, so thankyou
        again.

        Comment

        • ma740988

          #5
          Re: alignment issues

          On Sep 24, 4:43 am, James Kanze <james.ka...@gm ail.comwrote:
          On Sep 24, 8:13 am, Stephen Horne <sh006d3...@blu eyonder.co.ukwr ote:
          >
          >
          >
          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<typena me 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,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
          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-standardalignme nt
              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>::ty pe 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 dummyForAlignme nt ;
                  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>::dummyForA lignment' 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 dummyForAlignme nt '. What
          am I doing wrong?
          Thanks

          Comment

          • James Kanze

            #6
            Re: alignment issues

            On Oct 13, 3:54 am, ma740988 <ma740...@gmail .comwrote:
            On Sep 24, 4:43 am, James Kanze <james.ka...@gm ail.comwrote:
            On Sep 24, 8:13 am, Stephen Horne
            <sh006d3...@blu eyonder.co.ukwr ote:
            [...]
            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>::ty pe 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 dummyForAlignme nt ;
            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>::dummyForA lignment' 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 dummyForAlignme nt
            '. 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 dummyForAlignme nt ;
            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.)

            --
            James Kanze (GABI Software) email:james.kan ze@gmail.com
            Conseils en informatique orientée objet/
            Beratung in objektorientier ter Datenverarbeitu ng
            9 place Sémard, 78210 St.-Cyr-l'École, France, +33 (0)1 30 23 00 34

            Comment

            • Larry Evans

              #7
              Re: alignment issues

              On 09/24/08 01:13, Stephen Horne wrote:
              [snip]
              To get the alignment of an existing type, I use something like...
              [snip]
              Why not use boost's alignment_of:



              ?

              Comment

              • Chris M. Thomasson

                #8
                Re: alignment issues

                also, please check this crap out:



                Wow! ;^D

                Comment

                • Chris M. Thomasson

                  #9
                  Re: alignment issues

                  "ma740988" <ma740988@gmail .comwrote in message
                  news:e80fb452-c7e6-4a53-aac5-9ee00191a8ee@d3 1g2000hsg.googl egroups.com...
                  On Sep 24, 4:43 am, James Kanze <james.ka...@gm ail.comwrote:
                  On Sep 24, 8:13 am, Stephen Horne <sh006d3...@blu eyonder.co.ukwr ote:
                  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:



                  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:



                  here is some more context:



                  Comment

                  Working...