Please consider the two definitions below:
Foo foo;
unsigned char foo[sizeof(Foo)];
Are these guaranteed to have the same alignment, or will the second
definition have an alignment that is only modulo 1?
Thanks,
Dave
No.
The standard has the answer in 3.1-5 [basic.types]:
"Object types have alignment requirements (3.9.1, 3.9.2). The
alignment of a complete object type is an implementation-defined
integer value representing a number of bytes; an object is allocated
at an address that meets the alignment requirements of its object
type."
So, unless your Foo is a typedef for an array of unsigned char, then
your foo objects are two different types. Therefore both have their
own implementation-defined alignment en you can not portably assume
they will be the same.
To force the unsigned char array to have the same alignment as the Foo
(which is my goal), I'd like to put these together in a union.
However, Foo has a non-trivial constructor, so it may not be a member
of a union. Do I have any othre options?
Thanks to all!
Yes. Search this group and the moderated one for a solution that will
give the correct alignment (basically: a union containing all possible
types and the char representation).
/Peter
Allocate the char array dynamically:
char * fooArray = new char[sizeof(Foo)];
Now fooArray will be suitably aligned for a Foo type.
Greg
Unfortunately, allocating on the heap is verboten in our application.
Whether it makes sense or not, it is what it is and it will not pass
the design review.
The memory I'm trying to get properly aligned is actually going to be
static in a class and will have a singleton instance of the class
constructed in it via placement new.
class Foo
{
...
static unsigned char s_pInstance[];
};
unsigned char Foo::s_pInstance[sizeof(Foo)]; // Will have a Foo
constructed in it
The goal is to ensure that s_pInstance is suitably aligned to hold a
Foo. Is this possible within the bounds of the C++ language standard,
or is it an architecture issue (in which case I'm in the wrong group)?
In addition to my prvious response a minute ago, your comment brings
up a side issue.
In my original post, I showed the Foo and the char array being
constructed off of the heap, and the response was that the alignment I
seek is not guaranteed. However, your response clearly states that the
alignment I seek *will* be guaranteed if they are constructed on the
heap. So, I'd like to reconfirm -- are alignment issues indeed treated
differently on the heap than off?
Thanks for the response!
No, the "trick" is the use of the global operator new,
void* operator new(std::size_t size) throw(std::bad_alloc);
which is required to allocate bytes "suitably aligned to represent any
object of that size".
Note that the operator doesn't know the type of the object, but must
still obey the rule. We don't know how!
Bo Persson
If you are after a singleton implementation that doesn't use the heap,
why not use Meyers singleton?
The standard specifically states that new array of char or unsigned
char provides correct alignment for any object that fits in the
requested size. This explicitly allows what you are after, except that
it needs heap storage.
I had started with the Meyers singleton, but the problem I quickly ran
into was losing control over the sequence in which my singletons are
destructed. I have a lot of singletons, and there are dependencies
among them. So I must maintain control over their destruction order.
Having them constructed as static objects (i.e. as Meyers singletons)
deprives me of that control.
Since nobody else has mentioned it, I'll point out that the upcoming
C++0x standard will include an "alignment attribute" for specifying
alignment requirements. See n2798 section 7.6.2 [dcl.align]. In the
meantime, most compilers provide extensions. GCC supports something
like __attribute__ ((aligned (sizeof Foo))).
A traditional hack is to put the array in a union with the platform's
"most restrictive type;" see also page 186 of The C Programming Language.
You can attempt to calculate alignment of `Foo' objects like this:
___________________________________________________________________
#include <cstddef>
#include <cstdio>
struct Foo {
char a;
int b;
double c;
Foo(int b) {
// [...];
}
};
template<typename T>
size_t get_type_alignment() {
struct aligner {
char m_pad;
T m_obj;
};
return offsetof(aligner, m_obj);
}
int main() {
std::printf("%lu\n", (unsigned long)get_type_alignment<Foo>());
//--------------------------------------------------------------
std::puts("\n\n\n____________________________________________"
"____\npress <ENTER> to exit...");
std::fflush(stdin);
std::fflush(stdout);
std::getchar();
return 0;
}
___________________________________________________________________
Also, perhaps the following code will help you:
http://groups.google.com/group/comp.lang.c++/browse_frm/thread/f62bd4db8de1aad2
(read all...)
struct Foo {
int b;
char a;
double c;
Foo(int b) {
// [...];
}
};
#define ALIGN_POW2(mp_this, mp_type) ((mp_type)( \
(((std::ptrdiff_t)(mp_this)) + 1) & (-2) \
))
#define ALIGN(mp_this, mp_type, mp_align) ((mp_type)( \
(((std::ptrdiff_t)(mp_this)) + \
ALIGN_POW2(mp_align, std::ptrdiff_t) - 1) \
& (-ALIGN_POW2(mp_align, std::ptrdiff_t)) \
))
template<typename T, std::size_t CUSTOM_ALIGN = 0>
struct alignment {
struct aligner {
char m_pad;
T m_obj;
};
enum constant {
ALIGN_SIZE = (! CUSTOM_ALIGN) ? offsetof(aligner, m_obj) :
CUSTOM_ALIGN
};
template<typename T1>
static T1* align_ptr(void* ptr) {
return ALIGN(ptr, T1, ALIGN_SIZE);
}
class buffer {
enum constant {
REAL_SIZE = sizeof(T) + ALIGN_SIZE - 1
};
unsigned char m_raw[REAL_SIZE];
unsigned char* const m_align;
public:
buffer() : m_align(ALIGN(m_raw, unsigned char*, ALIGN_SIZE)) {
std::printf("buffer size: %lu\n", (unsigned long)REAL_SIZE);
std::printf("raw buffer: %p\n", (void*)m_raw);
std::printf("align buffer: %p\n", (void*)m_align);
}
unsigned char* get() const {
return m_align;
}
};
};
int main() {
alignment<Foo>::buffer buffer1;
Foo* foo = new (buffer1.get()) Foo(123);
foo->~Foo();
// 1024 byte buffer aligned on a 128 byte boundary...
alignment<unsigned char[1024], 128>::buffer buffer2;
//--------------------------------------------------------------
std::puts("\n\n\n____________________________________________"
"____\npress <ENTER> to exit...");
std::fflush(stdin);
std::fflush(stdout);
std::getchar();
return 0;
}
____________________________________________________________________
Any thoughts?
The representation of negative numbers is implementation-defined, so
this won't necessarily round mp_this up to an even multiple. Using
unsigned would give you well-defined behavior:
((mp_type) (((std::size_t) (mp_this) + 1) & -2u)
(I'd use uintptr_t instead of size_t, even though it's not part of C++)
> #define ALIGN(mp_this, mp_type, mp_align) ((mp_type)( \
> (((std::ptrdiff_t)(mp_this)) + \
> ALIGN_POW2(mp_align, std::ptrdiff_t) - 1) \
> & (-ALIGN_POW2(mp_align, std::ptrdiff_t)) \
> ))
I'm curious as to why you round mp_align up to a multiple of 2 here;
seems that ALIGN_POW2 can be eliminated entirely:
#define ALIGN( ptr, type, align ) \
((type) (((std::size_t) (ptr) + (align) - 1) & \
-(std::size_t) (align)))
But there's still the issue of assuming size_t can hold a pointer
without loss of bits (addressed in code below).
> template<typename T, std::size_t CUSTOM_ALIGN = 0>
> struct alignment {
> struct aligner {
> char m_pad;
> T m_obj;
> };
>
> enum {
> ALIGN_SIZE = (! CUSTOM_ALIGN) ? offsetof(aligner, m_obj) :
> CUSTOM_ALIGN
> };
This won't work for non-POD types, because offsetof cannot be applied to
them (if T is not a POD, then aligner isn't either):
18.1 para 5: The macro offsetof accepts a restricted set of type
arguments in this International Standard. type shall be a POD structure
or a POD union.
Perhaps you could eliminate this by using the size of aligner less the
size of T. Putting it all together into a simplified class:
#include <iostream>
#include <cstddef>
using namespace std;
template<typename T>
class alignment {
struct align_t {
char pad;
T obj;
};
public:
// Alignment requirement of T
enum { n = sizeof (align_t) - sizeof (T) };
// Size of buffer needed when its alignment is unknown
enum { buf = sizeof (align_t) - 1 };
};
// Aligns pointer by rounding up
template<typename T>
inline T* align( char* buf, size_t round = alignment<T>::n )
{
return (T*) (buf + (-(size_t) buf % round));
}
class Foo {
double d;
public:
// no default ctor
Foo( int ) { }
};
int main()
{
cout << "Foo's alignment requirement: " <<
(size_t) alignment<Foo>::n << '\n';
char* buf = new char [alignment<Foo>::buf];
Foo* foo = new (align<Foo>( buf )) Foo( 123 );
cout << (void*) buf << '\n';
cout << (void*) foo << '\n';
foo->~Foo();
delete [] buf;
}
[...]
> > To force the unsigned char array to have the same alignment
> > as the Foo (which is my goal), I'd like to put these
> > together in a union. However, Foo has a non-trivial
> > constructor, so it may not be a member of a union. Do I have
> > any othre options?
> Yes. Search this group and the moderated one for a solution
> that will give the correct alignment (basically: a union
> containing all possible types and the char representation).
I'm pretty sure you know this, but for precision's sake: the set
of all possible types is infinite, which means that you're going
to have to compromize some. Generally speaking, the set of all
basic types, plus a couple of different types of pointers
(void*, int*, struct X*, a pointer to a function, maybe pointers
to different types of members) should largely suffice. (It
would fail, of course, if in the implementation, the size of a
pointer depends on a hash code of the canonical type of the
pointed to object. Which is, I think, legal, but not something
I'd worry about encountering. It might change if the compiler
ensures some sort of special alignment for arrays, in order to
use some special hardware.)
In practice, this may result in a larger array than necessary if
the other type is small, e.g.:
struct Foo { char a[2] ; } ;
union {
unsigned char data[ sizeof( Foo ) ] ;
MaxAlignment dummyForAlignment ;
} ;
(where MaxAlignment is a union of all of the types). To avoid
this, you can do something like:
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 AlignType< T, char >::type c ;
typename AlignType< T, short >::type s ;
typename AlignType< T, int >::type i ;
typename AlignType< T, long >::type l ;
typename AlignType< T, long long >::type ll ;
typename AlignType< T, float >::type f ;
typename AlignType< T, double >::type d ;
typename AlignType< T, long double >::type ld ;
typename AlignType< T, void* >::type pc ;
typename AlignType< T, MaxAlign* >::type ps ;
typename AlignType< T, void (*)() >::type pf ;
// (I've yet to find a machine where I've needed
// more than the above.)
} ;
Since the required alignment for Foo can never be more than
sizeof(Foo), this only puts types whose size is less than or
equal to the size of Foo in the union.
--
James Kanze (GABI Software) email:james...@gmail.com
Conseils en informatique orientée objet/
Beratung in objektorientierter Datenverarbeitung
9 place Sémard, 78210 St.-Cyr-l'École, France, +33 (0)1 30 23 00 34
> news:eab8ea3f-5616-4fd8...@q1g2000vbn.googlegroups.com...
> > Please consider the two definitions below:
> > Foo foo;
> > unsigned char foo[sizeof(Foo)];
> > Are these guaranteed to have the same alignment, or will the
> > second definition have an alignment that is only modulo 1?
> You can attempt to calculate alignment of `Foo' objects like this:
Which isn't what he needs, but...
> ___________________________________________________________________
> #include <cstddef>
> #include <cstdio>
> struct Foo {
> char a;
> int b;
> double c;
> Foo(int b) {
> // [...];
> }
> };
> template<typename T>
> size_t get_type_alignment() {
> struct aligner {
> char m_pad;
> T m_obj;
> };
> return offsetof(aligner, m_obj);
This is undefined behavior if T isn't a POD (and Foo isn't). It
won't compile with at least one compiler I use.
> > news:eab8ea3f-5616-4fd8...@q1g2000vbn.googlegroups.com...
> > Foo(int b) {
> > // [...];
> > }
> > };
DOH!!! Yes, of course! My mistake. Thanks!
> > }
What about something like the following hack James?:
______________________________________________________________________
#include <cstddef>
#include <cstdio>
#include <climits>
#include <new>
template<typename T, std::size_t CUSTOM_ALIGN = 0U>
class alignment {
struct aligner_1 {
T m_obj;
};
struct aligner_2 {
char m_pad;
aligner_1 m_obj;
};
public:
enum constant {
ALIGN_SIZE = (! CUSTOM_ALIGN)
? sizeof(aligner_2) - sizeof(aligner_1)
: CUSTOM_ALIGN,
BUFFER_SIZE = sizeof(aligner_1) + (size_t)ALIGN_SIZE - 1U
};
static void* align_ptr(void* ptr) {
return ALIGN_SIZE > 1
? (void*)((((size_t)ptr) + ((size_t)ALIGN_SIZE - 1U))
& ~((size_t)ALIGN_SIZE - 1U))
: ptr;
}
private:
typedef char sassert[
ALIGN_SIZE > 0 &&
BUFFER_SIZE > 0 &&
ALIGN_SIZE <= INT_MAX &&
BUFFER_SIZE <= INT_MAX &&
ALIGN_SIZE > 1 ? ! ((size_t)ALIGN_SIZE % 2U) : 1 &&
sizeof(std::size_t) == sizeof(void*) ? 1 : -1
];
};
struct Base {
char x;
virtual void foo() = 0;
};
struct Foo : Base {
char a[5];
int b[3];
double c[2];
Foo(int x) {
// [...];
}
void foo() {
}
};
int main() {
std::printf(
"alignment of Foo: %lu\n"
"alignment of Foo*: %lu\n"
"alignment of Foo&: %lu\n",
(unsigned long)alignment<Foo>::ALIGN_SIZE,
(unsigned long)alignment<Foo*>::ALIGN_SIZE,
(unsigned long)alignment<Foo&>::ALIGN_SIZE
);
unsigned char foo_raw_buffer[
alignment<Foo>::BUFFER_SIZE
];
Foo* f = new (alignment<Foo>::align_ptr(foo_raw_buffer)) Foo(123);
std::printf(
"\nfoo_raw_buffer: %p\n"
"foo_raw_buffer_size: %lu\n"
"foo_align_buffer: %p\n",
(void*)foo_raw_buffer,
(unsigned long)alignment<Foo>::BUFFER_SIZE,
(void*)f
);
f->~Foo();
unsigned char page_raw_buffer[
alignment<unsigned char[8192], 8192>::BUFFER_SIZE
];
void* page_align_buffer =
alignment<unsigned char[8192], 8192>::align_ptr(page_raw_buffer);
std::printf(
"\npage_raw_buffer: %p\n"
"page_raw_buffer_size: %lu\n"
"page_align_buffer: %p\n",
(void*)page_raw_buffer,
(unsigned long)alignment<unsigned char[8192], 8192>::BUFFER_SIZE,
page_align_buffer
);
std::printf(
"\nalignment of char: %lu\n"
"alignment of short: %lu\n"
"alignment of int: %lu\n"
"alignment of long: %lu\n"
"alignment of float: %lu\n"
"alignment of double: %lu\n",
(unsigned long)alignment<char>::ALIGN_SIZE,
(unsigned long)alignment<short>::ALIGN_SIZE,
(unsigned long)alignment<int>::ALIGN_SIZE,
(unsigned long)alignment<long>::ALIGN_SIZE,
(unsigned long)alignment<float>::ALIGN_SIZE,
(unsigned long)alignment<double>::ALIGN_SIZE
);
//--------------------------------------------------------------
std::puts("\n\n\n____________________________________________"
"____\npress <ENTER> to exit...");
std::fflush(stdin);
std::fflush(stdout);
std::getchar();
return 0;
}
______________________________________________________________________
Does that compile on all your compilers? Odd that the broken code which used
`offsetof' macro on non-POD type compiles file on Comeau without warning. Oh
well, shi% happens.
How can I improve this hack?
;^(...
You make good points blargg. The hack was busted.
> [...]
> Perhaps you could eliminate this by using the size of aligner less the
> size of T. Putting it all together into a simplified class:
>
> #include <iostream>
> #include <cstddef>
> using namespace std;
>
> template<typename T>
> class alignment {
> struct align_t {
> char pad;
> T obj;
> };
> public:
> // Alignment requirement of T
> enum { n = sizeof (align_t) - sizeof (T) };
>
> // Size of buffer needed when its alignment is unknown
> enum { buf = sizeof (align_t) - 1 };
> };
Well, what if T is a reference type? Should that not be something like:
template<typename T>
class alignment {
struct align_1_t {
T obj;
};
struct align_2_t {
char pad;
align_1_t obj;
};
public:
// Alignment requirement of T
enum { n = sizeof (align_2_t) - sizeof (align_1_t) };
// Size of buffer needed when its alignment is unknown
enum { buf = sizeof (align_1_t) + n - 1 };
};
What am I missing here?
> > > }
My basic question is why? It doesn't enforce the alignment of
the buffer; it allocates a slightly larger buffer, and then
determines the first aligned address in it. A solution using a
union will force the compiler to align correctly to begin with.
[...]
> Does that compile on all your compilers?
Probably.
> Odd that the broken code which used `offsetof' macro on
> non-POD type compiles file on Comeau without warning.
It's more or less a library issue. G++ can detect the problem
because offsetof is defined as something like:
#define offsetof( a, b ) __buildin_offsetof( a, b )
and handled by the compiler. The library you're using with
Comeau probably exploits some other undefined behavior; the
classical implementation is something like:
#define offsetof( a, b ) ((size_t)(&((a*)0)->b))
This dereferences a null pointer, but in a way such that most
compilers won't actually generate any code for it. So it never
causes a compiler error, nor a core dump (but in some cases
where virtual bases are involved, it might give a wrong answer).
> My basic question is why? It doesn't enforce the alignment of
> the buffer; it allocates a slightly larger buffer, and then
> determines the first aligned address in it. A solution using a
> union will force the compiler to align correctly to begin with.
How can I use a union to align an arbitrary object up to, say, a 8192 byte
boundary? I can do this using the posted hack like:
_______________________________________________________________________
void foo() {
unsigned char page_raw_buffer[
alignment<unsigned char[8192], 8192>::BUFFER_SIZE
];
void* page_align_buffer =
alignment<unsigned char[8192], 8192>::align_ptr(page_raw_buffer);
}
_______________________________________________________________________
What am I missing?
You can't. The compiler aligns however it chooses, usually based on the
fundamental type of the strictest alignment that's present in the
struct/union. If you want a particular alignment, do it at run-time by
over-allocating and offsetting the pointer appropriately.