Reading Struct not Located at Four-boundary

F

Francesco S. Carta

The article is not very precise. It doesn't exclude some types,
for instance (non-object types, etc.).

Which are the non-object types?
And when T is not a POD, there can be padding before t in

I have skimmed the standard and I only found a mention about the fact
that a POD type cannot have initial padding, does that suffice to imply
that non-POD types can actually have initial padding or is there some
other explicit reference in the standard?
struct Foo { T t ; char c ; } ;

or even before c in

struct Foo { char c ; T t ; } ;

In the latter case, though, that's unlikely.

FWIW, I'm using a similar technique for "computing" a suitable
alignment down in my (experimental) version of fallible<> (the
non-experimental version has a T member and requires
default-construction, just like the Barton& Nackman one; the
new version drops the default-constructible requirement and uses
placement new---using, of course, a "suitably aligned" array of
unsigned chars).

Copy-pasting from there (beware: I have yet to review it---and
it started as a quick experiment):

template< typename T>
struct align_of
{
struct trick { // gps how to name it?
char c ;
T t ;
} ;

enum { v = sizeof( trick ) - sizeof( T ) } ;
enum { has_padding_at_end = v> sizeof( T ) } ; // should name
// this better

static std::size_t const value = has_padding_at_end
? sizeof( T )
: v
;
} ;

template< typename T>
std::size_t const
align_of< T>::value ;


When T is a POD the whole trick structure (which contains only a
T and a char) is a POD as well: thus there can't be padding
before the first member. (And I find it slightly clearer if the
char appears first.)

When T is not a POD, that padding is allowed. I see no reason
for the compiler to exploit that possibility with the struct
above. Anyway, if it is that "capricious" the whole thing breaks
down (numerical "coincidences" apart :)).

I suppose you could compute the initial padding by subtracting the
address of the object from the address of the first member - assuming
that is doable and useful...
Of course, this template is not exposed: it's only used
internally, to try one after another the POD types in a
predefined "list", in order to find the first of them (if any)
that has the same alignment as the type T on which fallible<> is
instantiated (more precisely: for which align_of<>::value is the
same as align_of< T>::value). At the end of the dance, it
doesn't matter what the alignment really is, numerically: it
picks the POD and puts it in the same union that contains the
array of unsigned chars.

Another thing I found perplexing in the article was

template<typename T>
struct Tchar {
T t;
char c;
};

#define strideof(T) \
((sizeof(Tchar<T>)> sizeof(T)) ? \
sizeof(Tchar<T>)-sizeof(T) : sizeof(T))


How can ever be the size of the struct be smaller than, or even
equal to, sizeof( T )? [footnote]
[footnote] I'm aware that in some cases an object may be
"smaller than its type" (virtual base classes etc.) but in this
case...

The author of that macro explains what (and why) has been addressed by
that ternary test: it's something about a possible and presumably
illegal padding reuse, I reported it also in the other replies to the
message you have just quoted from me.
 
F

Francesco S. Carta

On 21/08/2010 20.58, Francesco S. Carta wrote:
[...]
Indeed I should, I just need more study to actually associate some
well-grasped content to those labels ;-)


Of course you're not the only one who uses the standard terms. I
actually try to use them as long as I feel on firm ground.

Oh, but it wasn't addressed at you! And it was meant to be
humorous ("I feel lonely" :)). I just find that for these two
things using the standard terminology isn't very common.

Sorry, I understood that yours was a pun, I just forgot to interleave a
smile between those two sentences ;-)

The second sentence was just to say that I try to speak "formally and
technically" despite being a DIY full-time hobbyist, whatever that could
mean ;-)
No no, it was one of my "off at a tangent" thoughts. I was
thinking that the standard names work well because one of them
avoids the term "operator" altogether, referring to the
expression, instead. But *if* you need to talk about the
operator (the "lexical thing"), together with the operator
function, then things become more awkward. I meant: you'd have
to think more about how to avoid confusion.

Just to clarify:

3 + 2 additive "expression"
^--------- + operator

Similarly:

new T() new expression
^---------- new operator

An operator and an expression are two different things; it just
happens that in most cases we can "get away" by referring to the
expression (in fact, it usually makes more sense than referring
to the lexical notion, unless the topic of discussion is
compilers, etc.).

I hope I managed to explain what crossed my mind :)

You did, fully.

As I see them now and as I posted elsethread, "operator new" and "new
operator" do not look all that ambiguous anymore.

For the moment I feel that no additional thinking is needed to parse
them and to insert them into my sentences - but maybe that will change
within a couple of weeks, when the whole subject will pass to some
second plane of my attention ;-)
 
G

Gennaro Prota

Hmm, well, with the caveat that I've just been through a
sleepless night, I'll try to correct myself. (Ehm :-s)

[...]
And when T is not a POD, there can be padding before t in

struct Foo { T t ; char c ; } ;

or even before c in

struct Foo { char c ; T t ; } ;

True, but the sizeof() - sizeof() would still work.

For reference, we are trying to calculate the alignment of a
type T (or a multiple thereof) as:

struct Foo
{
char c ;
T t ;
} ;

align_of( T ) = sizeof( Foo ) - sizeof( T )

Hereby I'll call this "the technique".

It may be helpful for learning purposes to use the same example
that made me realize that I was in error (actually I knew all
the pieces that go into the puzzle, and shouldn't have needed
the example. Yet... I needed it :-/)

I was trying to make the technique fail, thinking of odd but
legal ways to add padding within the structure Foo.

Let's consider the case that the alignment of our T, as well as
its size in bytes, are 4. (In the following I'll use the
expression "at n" as a shorthand to "at n-byte boundaries").

One obvious think to do for the compiler is to align any
instance of Foo at 4 as well, putting 4 bytes before t (one for
the char plus 3 padding bytes).

But given that the char may be moved happily around and be
placed "everywhere", the compiler might "decide" (I think) that
instances of Foo will always be allocated at addresses that are
multiples of 2 but not of 4. That is, addresses of the form
2(2k-1) = 4k-2 (with k = 1, 2, 3, 4, ...) or, which is the same,
4(k-1)+2.

Just to fix our attention, let's put k=1. In this case, it would
put the char and one padding byte at the addresses 0x2 and 0x3,
then the subobject t at 0x04.

I thought that this would make the technique fail because I'd
got sizeof( Foo ) = 6 => align_of( T ) = 6 - 4 = 2.

But I was wrong. If the compiler does so, it has to add more
padding at the end. Consider, in fact, another Foo instance
which immediately follows the first one (think of an array). If
sizeof( Foo ) were 6 then the second instance would have the
char and the padding byte at 0x08 and 0x09, and then t at 0x0a:
misaligned! To make things line up properly the compiler would
have to add another 2 bytes (or 6, 10, 14...) at the end of the
struct. Thus the technique would work anyway.

I think that I got confused by thinking in terms of offset from
start only. In C, you may find a similar technique:

#define align_of( T ) offsetof( struct { char c; T t ; }, t )

This one *would* fail with my example. The sizeof() - sizeof()
is more powerful than offsetof, even in C.


It's also useful IMHO to spell out some guarantees on which all
the reasonings that are behind the technique may rest:

- T must not be an array type (actually I haven't thought much
about this; it may work, but I think it's just easier to treat
the case separately, saying that the alignment of an array
object is that of its first element (recursively))

- T must not be a reference type (we'd have problems due to how
sizeof works on a reference type)

- T must be instantiatable, and arrays of T must be
instantiatable too. Thus, for instance, no abstract classes,
no types whose constructors are all =delete.

- alignment must be a function *of the type*. In fact, we don't
even instantiate Foo but make reasonings (it's a multiple of
this, it's a multiple of that...) about the address at which
its instances will be allocated. In particular, we don't
consider the case that, say, instances within arrays are
aligned at 8 and "standalone instances" are aligned at 2. We
consider *one* alignment value.
 
J

Juha Nieminen

Paavo Helde said:
Accessing unaligned data is UB, depending on the platform this may crash
or produce wrong results. On some platforms it may works (notably x86),
but with a performance penalty.

UltraSparc is an example of a platform where trying to access unaligned
data will crash the program (with a "bus error" signal, to be precise).

Accessing unaligned data in portable code is indeed a no-no.
 
L

Larry Evans

On 08/21/10 13:31, Francesco S. Carta wrote:
[snip]
I still wonder if the method provided here can be trusted or not:

http://www.monkeyspeak.com/alignment/

Take a look at the following piece of code and its results on my setup
[MinGW 4.4.0, Windows7, AMD Athlon(tm) II Dual-Core M300 2.00 Ghz]

I wonder why "long double" gives a stride of 4 while "double" gives a
stride of 8 - where "stride" should stand for something like
"alignment", in the above linked page:

(maybe "long double" is stored as three floats or three longs in my
implementation?)
[snip]
See if:


http://www.boost.org/doc/libs/1_44_.../boost_typetraits/reference/alignment_of.html

doesn't give a better number. It's implementation:

http://svn.boost.org/svn/boost/trunk/boost/type_traits/alignment_of.hpp

does seem to use a similar method as the monkeyspeak one in some
cases; however, the comments in that code do suggest it doesn't always
get the right answer. Also, it uses a different order of T and char:

template <typename T>
struct alignment_of_hack
{
char c;
T t;
alignment_of_hack();
};
 
L

Larry Evans

On 08/22/10 04:15, Gennaro Prota wrote:
[snip]
struct Foo
{
char c ;
T t ;
} ;
[snip]
One obvious think to do for the compiler is to align any
instance of Foo at 4 as well, putting 4 bytes before t (one for
the char plus 3 padding bytes).

But given that the char may be moved happily around and be
placed "everywhere", the compiler might "decide" (I think) that
instances of Foo will always be allocated at addresses that are
multiples of 2 but not of 4. That is, addresses of the form
2(2k-1) = 4k-2 (with k = 1, 2, 3, 4, ...) or, which is the same,
4(k-1)+2.

Just to fix our attention, let's put k=1. In this case, it would
put the char and one padding byte at the addresses 0x2 and 0x3,
then the subobject t at 0x04.

I thought that this would make the technique fail because I'd
got sizeof( Foo ) = 6 => align_of( T ) = 6 - 4 = 2.

To be more explicit, lets call the Foo at the address designated by k=1
as foo, then the 6 comes from:
offset(Foo,t)+sizeof(T) - &foo
= 0x04+sizeof(T) - 0x2
= 0x04+0x04 - 0x2
= 0x08 - 0x2
= 0x06

Although it may seem obvious to you (as it does now to me)
it wasn't obvious to me before where the 6 came from :(
But I was wrong. If the compiler does so, it has to add more
padding at the end. Consider, in fact, another Foo instance
which immediately follows the first one (think of an array). If
sizeof( Foo ) were 6 then the second instance would have the
char and the padding byte at 0x08 and 0x09, and then t at 0x0a:
misaligned! To make things line up properly the compiler would
have to add another 2 bytes (or 6, 10, 14...) at the end of the
struct. Thus the technique would work anyway.

So, what's the sizeof(Foo) then? I'm not understanding why
you say the technique would work anyway. Are you saying it would
work if sizeof(Foo) is a certain value? Then what is that value
that would make it work? I'm guessing that only sizeof(Foo) = 8
would work as suggested by the above quoted sentence, repeated here:
> One obvious think to do for the compiler is to align any
> instance of Foo at 4 as well, putting 4 bytes before t (one for
> the char plus 3 padding bytes).

[snip]
 
G

Gennaro Prota

On 08/22/10 04:15, Gennaro Prota wrote:
[snip]
struct Foo
{
char c ;
T t ;
} ;
[snip]
One obvious think to do for the compiler is to align any
instance of Foo at 4 as well, putting 4 bytes before t (one for
the char plus 3 padding bytes).

But given that the char may be moved happily around and be
placed "everywhere", the compiler might "decide" (I think) that
instances of Foo will always be allocated at addresses that are
multiples of 2 but not of 4. That is, addresses of the form
2(2k-1) = 4k-2 (with k = 1, 2, 3, 4, ...) or, which is the same,
4(k-1)+2.

Just to fix our attention, let's put k=1. In this case, it would
put the char and one padding byte at the addresses 0x2 and 0x3,
then the subobject t at 0x04.

I thought that this would make the technique fail because I'd
got sizeof( Foo ) = 6 => align_of( T ) = 6 - 4 = 2.

To be more explicit, lets call the Foo at the address designated by k=1
as foo, then the 6 comes from:
offset(Foo,t)+sizeof(T) - &foo
= 0x04+sizeof(T) - 0x2
= 0x04+0x04 - 0x2
= 0x08 - 0x2
= 0x06

No. It came from 2 (the offset before t in the layout I
imagined) plus sizeof( T ): I thought, stupidly, that the
compiler could "terminate" the structure Foo just after t.
Although it may seem obvious to you (as it does now to me)
it wasn't obvious to me before where the 6 came from :(


So, what's the sizeof(Foo) then?

It can be 8, 12, 16, ... but not 6. See also what is called
Appendix 2 in the article Francesco linked to.
I'm not understanding why
you say the technique would work anyway.

Because both sizeof( Foo ) and sizeof( T ) are multiples of the
alignment of T. Thus their difference is, too.
 
G

Gennaro Prota

Which are the non-object types?

See and [basic.types]/5 and [basic.types]/9. (For the non-"non-"
version :))
I have skimmed the standard and I only found a mention about the fact
that a POD type cannot have initial padding, does that suffice to imply
that non-POD types can actually have initial padding or is there some
other explicit reference in the standard?

I see no explicit reference, but the rules seem to be carefully
crafted to allow it. I'm sure someone will come up with an
example where it is necessary. I'm just too tired right now to
think of anything sensible.

[...]
Another thing I found perplexing in the article was

template<typename T>
struct Tchar {
T t;
char c;
};

#define strideof(T) \
((sizeof(Tchar<T>)> sizeof(T)) ? \
sizeof(Tchar<T>)-sizeof(T) : sizeof(T))


How can ever be the size of the struct be smaller than, or even
equal to, sizeof( T )? [footnote]
[footnote] I'm aware that in some cases an object may be
"smaller than its type" (virtual base classes etc.) but in this
case...

The author of that macro explains what (and why) has been addressed by
that ternary test: it's something about a possible and presumably
illegal padding reuse, I reported it also in the other replies to the
message you have just quoted from me.

OK. It had never occurred to me but, apparently, it has been
asked, even to the C committee. See bullet g of

<http://www.open-std.org/jtc1/sc22/wg14/www/docs/dr_074.html>

I don't have the C90 standard so I can't tell what the content
of subclause 6.3 is. I suspect that it's something related to
accessing the object at runtime, though (such as memset()'ing t
and getting something in c). Could anyone provide a quotation?

So, if my guess is right, one might claim that if the struct is
never instantiated... Or he can invent cases that are slightly
different from question g in that DR... I'd say that the intent
is just to disallow it, and quickly skimming through a couple of
comp.std.c threads seems to confirm my gut feeling.

As Francis Glassborow put it in one of the posts that I read:

I do not think you need specific text [that prohibits that
reusage] because as you have already noted, such an
arrangement would result in storage for a variable being
changed without program instruction. Such behaviour must be
wrong else we might as well all give up and go home.

In fact, when the "questioning" reaches such a fundamental level
I begin to hate C++. Especially since the standard doesn't
provide ground to prove these theorems, even if you are willing
to (but even if you are... how can you program if you have to
prove theorems in the language at every corner).

BTW, that DR also has some bad news in the answer to bullet a.
For the little that I've been able to gather from the new C++0x
requirements, this seems an incompatibility between C and C++
(because C++ seems to intend that the alignment is a function of
the type: an object of the same type has the same alignment. But
as you might have seen, I've asked for a confirmation about
this, without success. In fact, I'm looking for an effective way
to deal with it before C++0x is finalized. Some national body
should probably help, as a DR would just be dealt with after the
publication of the standard).
 
L

Larry Evans

On 08/21/10 06:30, Francesco S. Carta wrote:
[snip]
I've created a struct that occupies 64 bytes of storage, then I
dynamically allocated it and I checked its address to see if, as I was
expecting, it was a multiple of 64. As it turned out, it wasn't, showing
me that my assumption was stupid at best.

I have no idea about where I have taken that misconception from, I could
very well have made it up all by myself.
[snip]

Hi Francesco.

I struggled a few yrs (months?) ago about that and think I've
figured it out.

The alignment of your 64 byte long structure is dependent on the
types contained in the structure.

Hi Larry, thank you for your post.

Indeed, I suspected something like that, by now I see that regardless of
what I am allocating, the "largest" alignment amounts to 32 bytes on my
system, so it all should come down to the most stringent alignment
required for fundamental types.
Using variadic template:

I'm snipping all of your post for brevity as...

Sorry if this seems complicated. It is, at least to me :(

...believe me, all of that is not complicated for me, it is just plain
unintelligible: I never really put my hands on such advanced features of
the upcoming new C++ standard, I've only read about some of them in some
article here and there, I'm afraid I'll have to stay on the current
standard for some good time still, as there are too many basic concepts
that still trick me even if I already have acquired some good bits on
all the existing features.
The statement from my previous post:

alignof(C) == fold(lcm,1,alignof(T)...)

is suggested by:
Can A(struct foo) be greater than the least common multiple of
A(type_1), A(type_2), ..., A(type_n),
where type_1 to type_n are the types of the elements of struct foo?

from the defect report (DR) reference Gennaro gave (thanks Gennaro)
in another post:

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

More explicitly:

alignof(T)... in my post
corresponds to:
A(type_1), A(type_2), ..., A(type_n) from the DR.

alignof(C) in my post
corresponds to:
A(struct foo) from the DR.

Does that make things clearer? I did write some justifcation
for this and uploaded it to the boost vault. IIRC, the
justification is just in a .txt file and I think (judging
from the description shown on the web) that it located somewhere
in the zip file here:

http://www.boostpro.com/vault/index.php?action=downloadfile&
filename=aligned_types.2.zip&directory=variadic_templates&

I'm pretty sure the .txt file doesn't use in variadic template
notation; so, hopefully that won't be part of any roadblock to
your understanding.

HTH.

-Larry
 
F

Francesco S. Carta

Which are the non-object types?

See and [basic.types]/5 and [basic.types]/9. (For the non-"non-"
version :))

Ah, yes, of course, silly me...
I see no explicit reference, but the rules seem to be carefully
crafted to allow it. I'm sure someone will come up with an
example where it is necessary. I'm just too tired right now to
think of anything sensible.

I'm really curious to see an example where such initial padding could
come useful... anybody else still keeping an eye here?
[...]
Another thing I found perplexing in the article was

template<typename T>
struct Tchar {
T t;
char c;
};

#define strideof(T) \
((sizeof(Tchar<T>)> sizeof(T)) ? \
sizeof(Tchar<T>)-sizeof(T) : sizeof(T))


How can ever be the size of the struct be smaller than, or even
equal to, sizeof( T )? [footnote]
[footnote] I'm aware that in some cases an object may be
"smaller than its type" (virtual base classes etc.) but in this
case...

The author of that macro explains what (and why) has been addressed by
that ternary test: it's something about a possible and presumably
illegal padding reuse, I reported it also in the other replies to the
message you have just quoted from me.

OK. It had never occurred to me but, apparently, it has been
asked, even to the C committee. See bullet g of

<http://www.open-std.org/jtc1/sc22/wg14/www/docs/dr_074.html>

I don't have the C90 standard so I can't tell what the content
of subclause 6.3 is. I suspect that it's something related to
accessing the object at runtime, though (such as memset()'ing t
and getting something in c). Could anyone provide a quotation?

So, if my guess is right, one might claim that if the struct is
never instantiated... Or he can invent cases that are slightly
different from question g in that DR... I'd say that the intent
is just to disallow it, and quickly skimming through a couple of
comp.std.c threads seems to confirm my gut feeling.

As Francis Glassborow put it in one of the posts that I read:

I do not think you need specific text [that prohibits that
reusage] because as you have already noted, such an
arrangement would result in storage for a variable being
changed without program instruction. Such behaviour must be
wrong else we might as well all give up and go home.

In fact, when the "questioning" reaches such a fundamental level
I begin to hate C++. Especially since the standard doesn't
provide ground to prove these theorems, even if you are willing
to (but even if you are... how can you program if you have to
prove theorems in the language at every corner).

BTW, that DR also has some bad news in the answer to bullet a.
For the little that I've been able to gather from the new C++0x
requirements, this seems an incompatibility between C and C++
(because C++ seems to intend that the alignment is a function of
the type: an object of the same type has the same alignment. But
as you might have seen, I've asked for a confirmation about
this, without success. In fact, I'm looking for an effective way
to deal with it before C++0x is finalized. Some national body
should probably help, as a DR would just be dealt with after the
publication of the standard).

Thanks for the references.

As I mentioned elsethread, I'm almost completely unaware of the details
of the new standard, I only had a read to some articles here and there,
but sooner or later I'll have to dip my fingers there.

Unfortunately I cannot give any help about your reports... isn't there
in the committee some Italian entity or person that you could contact to
focus a bit of attention on those issues?

Well maybe you just need to exercise some more patience, your reports
can still get a feedback before the new publication, I think.

Or eventually, I wonder whether the DR is not the proper shape to
present those issues, as you say those should be addressed after the
publication... but I'm far from my firm ground, so I'll be better
shutting up before writing some (further) silliness ;-)
 
Ö

Öö Tiib

I'm really curious to see an example where such initial padding could
come useful... anybody else still keeping an eye here?

Perhaps it is not about initial padding, but about stuff that may be
before first data member (for example for polymorphism or RTTI). It is
up to implementation so standard is careful not guaranteeing nor
denying that something is there.
 
L

Larry Evans

On 08/21/10 13:31, Francesco S. Carta wrote:
[snip]
I still wonder if the method provided here can be trusted or not:

http://www.monkeyspeak.com/alignment/
[snip]
I'm puzzled by the strideof(T) macro.
I would have thought sizeof(Tchar<T>) > size(T) would always be
true. OTOH, maybe the compiler knows that T has some padding at
the end where it puts the 'char c'.

The author motivates the above macro exactly for that "padding reuse"
possibility, see the second paragraph:

[quote from http://www.monkeyspeak.com/alignment/ ] [snip]
The second case is if T already has some padding in it, and the compiler
chooses to reuse some of T's padding to store the extra char. In that
case, Tchar will be the same size as T, and our subtraction will yield
zero. When that happens, our macro defaults to sizeof(T), which is not
optimal but is at least known to be a multiple of T's stride. (There is
some dispute as to whether this case can arise--some believe that it is
illegal for a compiler to reuse padding like this. Either way, our
technique deals with it.)
[/QUOTE]
[snip]
From http://www.open-std.org/jtc1/sc22/wg14/www/docs/dr_074.html,
response g) says such reuse of padding (called sharing of storage
in the ref) is not allowed.
 
L

Larry Evans

On 08/21/10 16:16, Francesco S. Carta wrote: [snip]
[quote from http://www.monkeyspeak.com/alignment/ ] [snip]
The second case is if T already has some padding in it, and the compiler
chooses to reuse some of T's padding to store the extra char. In that
case, Tchar will be the same size as T, and our subtraction will yield
zero. When that happens, our macro defaults to sizeof(T), which is not
optimal but is at least known to be a multiple of T's stride. (There is
some dispute as to whether this case can arise--some believe that it is
illegal for a compiler to reuse padding like this. Either way, our
technique deals with it.)
[snip]
From http://www.open-std.org/jtc1/sc22/wg14/www/docs/dr_074.html,
response g) says such reuse of padding (called sharing of storage
in the ref) is not allowed.
[/QUOTE]
I've a feeling of deja vu. This reuse of padding was actually
done to create a tagged union as described in this thread:

http://sourceforge.net/mailarchive/[email protected]

In summary, Joel had a utree which was a tagged union; however,
he had to store the tag somewhere which means he had to create
something like:

struct tagged_union
{ u_type u_part;
char tag_part;
};

where u_type was "equivalent" to some union type.
However, that union type had some padding due to
alignment requirements and, to save space, joel
wanted to put the tag_part in that padding.
This was done by store the whole thing a a char
buffer and using template metaprogramming to
extract the u_part and tag_part.

Hope you find it interesting.

-regards,
Larry
 
J

James Kanze

Gennaro Prota <[email protected]>, on 22/08/2010 20:56:33, wrote:

[...]
I'm really curious to see an example where such initial
padding could come useful... anybody else still keeping an eye
here?

It might depend on what you consider "padding". What is certain
is that if C is not a PODS, then there is no guarantee that the
address of a C object is the same as the address of its first
member. In a typical implementation, for example:

struct C
{
int a;
virtual ~C(); // So not PODS
};

C c;

, (void*)&c and (void*)&c.a will not compare equal. (Drop the
virtual destructor, and they are required to by the standard.)

Basically, all the standard is doing is allowing implementations
additional freedom with regards to layout if the type isn't POD.
All of the implementations I know use this freedom in some
specific cases.
 
F

Francesco S. Carta

On 08/22/10 18:59, Larry Evans wrote:

I've a feeling of deja vu. This reuse of padding was actually
done to create a tagged union as described in this thread:

http://sourceforge.net/mailarchive/[email protected]


In summary, Joel had a utree which was a tagged union; however,
he had to store the tag somewhere which means he had to create
something like:

struct tagged_union
{ u_type u_part;
char tag_part;
};

where u_type was "equivalent" to some union type.
However, that union type had some padding due to
alignment requirements and, to save space, joel
wanted to put the tag_part in that padding.
This was done by store the whole thing a a char
buffer and using template metaprogramming to
extract the u_part and tag_part.

Hope you find it interesting.

Indeed, I'm trying to sum up all these references to get a better grasp
on the subject, thanks for them Larry.
 
F

Francesco S. Carta

Perhaps it is not about initial padding, but about stuff that may be
before first data member (for example for polymorphism or RTTI). It is
up to implementation so standard is careful not guaranteeing nor
denying that something is there.

I understand, thank you for the note Öö.

An explicit mention in the standard would have been nice, though, just
to avoid people wandering around looking for something that is there
just as an implication of something else ;-)
 
F

Francesco S. Carta

[...]
And when T is not a POD, there can be padding before t in
I have skimmed the standard and I only found a mention
about the fact that a POD type cannot have initial padding,
does that suffice to imply that non-POD types can actually
have initial padding or is there some other explicit
reference in the standard?
I see no explicit reference, but the rules seem to be
carefully crafted to allow it. I'm sure someone will come up
with an example where it is necessary. I'm just too tired
right now to think of anything sensible.
I'm really curious to see an example where such initial
padding could come useful... anybody else still keeping an eye
here?

It might depend on what you consider "padding". What is certain
is that if C is not a PODS, then there is no guarantee that the
address of a C object is the same as the address of its first
member. In a typical implementation, for example:

struct C
{
int a;
virtual ~C(); // So not PODS
};

C c;

, (void*)&c and (void*)&c.a will not compare equal. (Drop the
virtual destructor, and they are required to by the standard.)

Basically, all the standard is doing is allowing implementations
additional freedom with regards to layout if the type isn't POD.
All of the implementations I know use this freedom in some
specific cases.

I see, thanks for the details James.

As I said elsethread, an explicit mention in the standard would have
been nice.
 
G

Gennaro Prota

On 22/08/2010 23.03, Francesco S. Carta wrote:
[...]
[...]
Thanks for the references.

As I mentioned elsethread, I'm almost completely unaware of the details
of the new standard, I only had a read to some articles here and there,
but sooner or later I'll have to dip my fingers there.

I'm not very up-to-date either. But since I've been playing with
alignment as of lately (due to the experimental fallible<> I
mentioned elsewhere) I had a look at what C++0x has to say about
it, so that I would already code on the ground of what will be
guaranteed (and likely already holds in practice). Alas, the
result was the long message I posted here under the subject

"On alignment (final committee draft for C++0x and n1425 for C1X)"
Unfortunately I cannot give any help about your reports... isn't there
in the committee some Italian entity or person that you could contact to
focus a bit of attention on those issues?

Don't you know that Italy doesn't exist programming-wise? We
were once decent at playing football, but as it concerns
programming and C++ in particular...
Well maybe you just need to exercise some more patience, your reports
can still get a feedback before the new publication, I think.

Or eventually, I wonder whether the DR is not the proper shape to
present those issues, as you say those should be addressed after the
publication... but I'm far from my firm ground, so I'll be better
shutting up before writing some (further) silliness ;-)

No, the contrary! :) IMHO the whole paragraph is so broken that
it should be fixed *before* publication. If you look at the core
or library DR lists you'll see that there are at times issues
that remain open for ten years or more. Add that even when the
whole thing is "fixed" it will require compiler vendors to
(monitor the committee decisions and) carefully check if their
implementation respects the resolution. (So: twenty years? Is
that a good guess?)

I had a vague idea to contact someone on the French body
(ahehm... James? Still keeping an eye?) but I'm also
increasingly feeling discouraged. It seems that few people care.
I already wasted a lot of time writing the post (although
noticing the problems took really a nanosecond).
 
G

Gennaro Prota

On 22/08/2010 20.45, Gennaro Prota wrote:
[...]
Because both sizeof( Foo ) and sizeof( T ) are multiples of the
alignment of T. Thus their difference is, too.

I should have been more precise.

It "works" if the requirement is to get the true alignment or a
multiple of it.

In some cases, however (including my usage for the fallible<>
template), this requirement isn't useful.

What I was after was for the buffer in which I'll placement-new
my T to have exactly the same size as T.

Of course I can't just do

union {
unsigned char buffer[ sizeof( T ) ] ;
T dummy ;
} ;

because not all T's can go into a union. So, my idea was to
choose, for each T, a POD type T2 having *the same alignment* as
T (if it exists), and put that in the union. But if the align_of
template begins to "lie" I'm in trouble: it might tell me that
both T and T2 have an alignment of 4 whereas, for instance, T
really aligns at 4 but T2 has a true alignment of 2. Bang, we
are dead. (Note the switch from "I" to "we" :))

And what's worse we might be dead at intermittent times (not
necessarily the same moments for "I" and "we").

A scenario where it is still useful, instead, and probably the
one for which the various boost's and then C++0x's facilities
were thought, is when you have a buffer *large enough* and don't
care to waste some of it. In that case, for instance, you may be
able to do some simple math and discard some bytes at the start.

But if I wanted to leave unused space then I'd just resort to
the old trick of using a union ("MaxAlign") with most of the
fundamental types in it. (Which is what I was doing; all this
dance started exactly as an experimental attempt to save
allocation space with respect to using MaxAlign).

So, one thing that I'd be glad to have now is a way to tell if
two types have the same alignment (meant as *minimum*
alignment), without necessarily knowing what the alignment is.
If you know of any technique to do this please voice your voice
:)

Besides that, there's also a completely different approach which
has been wandering though my mind for a while. But I won't make
my ruminations public until I've some feeling that they may
really work.
 
L

Larry Evans

On 08/28/10 12:48, Gennaro Prota wrote:
[snip]
But if the align_of
template begins to "lie" I'm in trouble: it might tell me that
both T and T2 have an alignment of 4 whereas, for instance, T
really aligns at 4 but T2 has a true alignment of 2. Bang, we
are dead. (Note the switch from "I" to "we" :))

But if align_of "lies", isn't that a compiler bug?

[snip]
 

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,733
Messages
2,569,440
Members
44,830
Latest member
ZADIva7383

Latest Threads

Top