Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

This will work or not?

188 views
Skip to first unread message

Melzzzzz

unread,
Aug 31, 2016, 8:59:32 AM8/31/16
to
Code in question is like this:

struct Problem{
uint32_t a;
uint32_t b;
uint64_t c;
uint32_t d;
bool check_it() {
for (uint32_t* i = &a;i != &d; ++i)
if (*i>0) return true;
return false;
}

};

I am not sure if this will work, so if someone has clear explanation
why it will work (or not) , I would be grateful.

David Brown

unread,
Aug 31, 2016, 9:20:57 AM8/31/16
to
I don't think you are guaranteed that a, b, c, and d follow each other
in the structure layout (though it is very likely to be the case). With
a pointer to a single item &a, incrementing the pointer is undefined
behaviour - as is accessing *i. And accessing the uint64_t member using
an uint32_t* pointer contradicts aliasing restrictions.

All in all, the compiler is free to assume that this code is full of
undefined behaviour, therefore you don't really care what it does -
therefore it can all be optimised to "return true", "return false", or
even "launch nasal daemons". (This last option is legal for the
compiler, but thankfully unlikely in practice.)

You can make it legal with:

struct Problem {
union {
struct {
uint32_t a;
uint32_t b;
uint64_t c;
uint32_t d;
}
uint32_t as_array[5];
}
bool check_it() {
for (uint32_t* i = &as_array[0]; i != &as_array[4]; ++i)
if (*i > 0) return true;
return false;
}
}

(Any issues regarding anonymous unions/structs are left as an exercise
for the reader :-)

Manfred

unread,
Aug 31, 2016, 9:45:20 AM8/31/16
to
You need to specify __attribute__((__packed__)) for a, b, c, d (esp. d)
Moreover, the guaranteed ordering of a, b, c, d needs to be verified
with the standard:
iso 9.2.13 (draft 2014-11-19):
"Nonstatic data members of a (non-union) class with the same access
control (Clause 11) are allocated so that later members have higher
addresses within a class object. The order of allocation of non-static
data members with different access control is unspecified (Clause 11).
Implementation alignment requirements might cause two adjacent members
not to be allocated immediately after each other; so might requirements
for space for managing virtual functions (10.3) and virtual base classes
(10.1)."

Obviously the test may only work for comparison with 0.
I would not classify this practice as good, in the sense that I would
not do this in production code.

Best Regards,
M.

Melzzzzz

unread,
Aug 31, 2016, 10:00:06 AM8/31/16
to
On Wed, 31 Aug 2016 15:45:07 +0200
Manfred <non...@invalid.add> wrote:

> On 8/31/2016 2:59 PM, Melzzzzz wrote:
> > Code in question is like this:
> >
> > struct Problem{
> > uint32_t a;
> > uint32_t b;
> > uint64_t c;
> > uint32_t d;
> > bool check_it() {
> > for (uint32_t* i = &a;i != &d; ++i)
> > if (*i>0) return true;
> > return false;
> > }
> >
> > };
> >
> > I am not sure if this will work, so if someone has clear explanation
> > why it will work (or not) , I would be grateful.
> >
>
> You need to specify __attribute__((__packed__)) for a, b, c, d (esp.
> d)

Oh I forgot to say that that attribute is specified.


Moreover, the guaranteed ordering of a, b, c, d needs to be
> verified with the standard:
> iso 9.2.13 (draft 2014-11-19):
> "Nonstatic data members of a (non-union) class with the same access
> control (Clause 11) are allocated so that later members have higher
> addresses within a class object. The order of allocation of
> non-static data members with different access control is unspecified
> (Clause 11). Implementation alignment requirements might cause two
> adjacent members not to be allocated immediately after each other; so
> might requirements for space for managing virtual functions (10.3)
> and virtual base classes (10.1)."
>
> Obviously the test may only work for comparison with 0.
> I would not classify this practice as good, in the sense that I would
> not do this in production code.

I agree.

>
> Best Regards,
> M.
>


mark

unread,
Aug 31, 2016, 10:05:32 AM8/31/16
to
On 2016-08-31 15:20, David Brown wrote:
> On 31/08/16 14:59, Melzzzzz wrote:
>> > Code in question is like this:
>> >
>> > struct Problem{
>> > uint32_t a;
>> > uint32_t b;
>> > uint64_t c;
>> > uint32_t d;
>> > bool check_it() {
>> > for (uint32_t* i = &a;i != &d; ++i)
>> > if (*i>0) return true;
>> > return false;
>> > }
>> >
>> > };
>> >
>> > I am not sure if this will work, so if someone has clear explanation
>> > why it will work (or not) , I would be grateful.
>> >
> I don't think you are guaranteed that a, b, c, and d follow each other
> in the structure layout (though it is very likely to be the case). With
> a pointer to a single item &a, incrementing the pointer is undefined
> behaviour - as is accessing *i.

I don't think so. My reading of the standard is that code would have
well-defined and legal behavior if c was uint32_t and no padding is used.

C++14 5.7 (Additive operators):
<<<
84) An object that is not an array element is considered to belong to a
single-element array for this purpose
>>>

It is legal to point 1 element past the array size. So "&a + 1" is legal
and will in turn point to another valid uint32_t.

David Brown

unread,
Aug 31, 2016, 10:19:51 AM8/31/16
to
No, I don't think that is right. "&a + 1" is legal - but it does not
point to another valid uint32_t, and you can't dereference it. You are
allowed to make a pointer move one step off the end of an array, so that
you can make comparisons with "<" in your loops. But you can't use the
pointer for accessing anything.


Scott Lurndal

unread,
Aug 31, 2016, 10:20:10 AM8/31/16
to
David Brown <david...@hesbynett.no> writes:
>On 31/08/16 14:59, Melzzzzz wrote:
>> Code in question is like this:
>>
>> struct Problem{
>> uint32_t a;
>> uint32_t b;
>> uint64_t c;
>> uint32_t d;
>> bool check_it() {
>> for (uint32_t* i = &a;i != &d; ++i)
>> if (*i>0) return true;
>> return false;
>> }
>>
>> };
>>
>> I am not sure if this will work, so if someone has clear explanation
>> why it will work (or not) , I would be grateful.
>>
>
>I don't think you are guaranteed that a, b, c, and d follow each other
>in the structure layout (though it is very likely to be the case).

It is guaranteed that the fields will be ordered in memory
as it in the source. It is not guaranteed that there will not be
padding between the fields unless a compiler dependent mechanism to
specified "packed" for the struct is present.

David Brown

unread,
Aug 31, 2016, 10:23:09 AM8/31/16
to
And note that at least one major compiler - gcc - /did/ re-organise the
ordering in structs when appropriate optimisation flags were enabled.
It would not do so if you took addresses like this, and the optimisation
has been removed in later versions of gcc (because it played badly with
link-time optimisation), but compilers might make such re-organisations
in the future.

Of course, individual implementations might guarantee that this works,
even though the standards don't.

Manfred

unread,
Aug 31, 2016, 11:06:29 AM8/31/16
to
On 8/31/2016 4:22 PM, David Brown wrote:
>> Moreover, the guaranteed ordering of a, b, c, d needs to be verified
>> with the standard:
>> iso 9.2.13 (draft 2014-11-19):
>> "Nonstatic data members of a (non-union) class with the same access
>> control (Clause 11) are allocated so that later members have higher
>> addresses within a class object. The order of allocation of non-static
>> data members with different access control is unspecified (Clause 11).
>> Implementation alignment requirements might cause two adjacent members
>> not to be allocated immediately after each other; so might requirements
>> for space for managing virtual functions (10.3) and virtual base classes
>> (10.1)."
>
> And note that at least one major compiler - gcc - /did/ re-organise the
> ordering in structs when appropriate optimisation flags were enabled.
> It would not do so if you took addresses like this, and the optimisation
> has been removed in later versions of gcc (because it played badly with
> link-time optimisation), but compilers might make such re-organisations
> in the future.
>
> Of course, individual implementations might guarantee that this works,
> even though the standards don't.
>
Data members ordering is guaranteed by the standard, but objections
still hold in that, besides packing issues, the same standard in
principle allows for:
- interleaving of data members with different access control, so that a
private member may fall in between a bunch of public ones.
- "space for managing virtual functions and virtual base classes" to
fall anywhere.
Maybe your proposal of union+array could prevent this?

Bo Persson

unread,
Aug 31, 2016, 12:53:15 PM8/31/16
to
On 2016-08-31 15:20, David Brown wrote:
This might work in C, but a problem is that the C++ standard says:

9.3 Unions
"In a union, a non-static data member is active if its name refers to an
object whose lifetime has begun and has not ended (3.8). At most one of
the non-static data members of an object of union type can be active at
any time, that is, the value of at most one of the non-static data
members can be stored in a union at any time. "

So, if the struct with a, b, c, and d is active, as_array is not
"stored" and cannot be read. You can't read an object that isn't there!



Bo Persson

David Brown

unread,
Aug 31, 2016, 1:30:11 PM8/31/16
to
Apparently, you are not allowed to access the different parts of the
union as I had thought. My knowledge of such details in C++ is a good
deal less than my knowledge of C, and my knowledge of C has holes too!

However, the standard does not guarantee that data members are ordered
in the same way as they are declared in the struct - it guarantees that
they /appear/ that way to any code with defined behaviour. If code does
not do anything that might be influenced by the ordering, or the code
that is dependent on the order has undefined behaviour (as in this
case), then the compiler /can/ re-order the data members. This is all
part of the "as if" rule - compilers can generate anything they want, as
long as the code runs "as if" it followed the abstract machine and C or
C++ rules directly.

So if you have a struct, and use things like the "offsetof" macro on its
fields, the compiler is going to have to allocate members in the
specified order. But if you have a "struct { int a; int b; }" used as a
local variable without ever referring to their addresses, not only can
the compiler swap a and b, but it can put them in registers, or even
omit one of the members altogether if it can be "optimised away".


Vir Campestris

unread,
Aug 31, 2016, 4:08:22 PM8/31/16
to
Depends what you mean by "work".

There is no guarantee that the first time you increment the pointer to
get from a it will point to b. There may be padding to ensure correct
alignment. Some processors require this, and IIRC the packed attribute
is not part of the C standard. Even then Gnu don't say exactly what it
packs to.

Andy

Chris Vine

unread,
Aug 31, 2016, 4:52:27 PM8/31/16
to
On Wed, 31 Aug 2016 19:29:57 +0200
David Brown <david...@hesbynett.no> wrote:
[snip]
> Apparently, you are not allowed to access the different parts of the
> union as I had thought. My knowledge of such details in C++ is a
> good deal less than my knowledge of C, and my knowledge of C has
> holes too!

It has undefined behaviour in C89, and C99 as originally printed. It
has defined behaviour in C99 with Technical Corrigendum 3 applied and in
C11, except that if there are padding bytes they can have a trap
representation (§6.2.6.1/6 and /7 of C11 read with footnote 95 of
§6.5.2.3/3 if you want the reference). The latter (trap
representations) can be ignored on any architecture running C++. GCC
and clang permit type punning through unions in C++ in the same way as
an extension.

To make it portable I guess you could put the code in a separate
translation unit compiled as C11 and link to that in your C++ code. It
seems a bit overly complicated though.

Chris

Alf P. Steinbach

unread,
Aug 31, 2016, 8:29:35 PM8/31/16
to
Formally there can be padding (except before the first item), and
therefore formally you're in UB-land.

And the formal UB means that an impractical compiler, a perverse
compiler, can treat this as an opportunity to optimize away all of the
checking. After all if it incurs UB, then in a correct program it would
never be executed. So to the perverse compiler it's just dead code.

But assuming a non-perverse compiler, you can simply

static_assert( sizeof( Problem ) == 4*sizeof( uint32_t ) );

... and, under the no perversity assumption, that makes the code
portable in the sense that sometime in the future it simply won't
compile on the so far not yet created system where it wouldn't work.

Note: the /order/ of the items in memory is guaranteed, because there is
no intervening access specifier.

• • •

All that said, a safe alternative is to do this:

#include <algorithm>
#include <array>
#include <stdint.h>

namespace my {
using std::array;

struct Problem
{
using Item = uint32_t;
struct Id{ enum Enum{ a, b, c, d, _ }; };

array<Item, Id::_> items;

auto item( Id::Enum const id ) -> Item& { return items[id]; }
auto item( Id::Enum const id ) const -> Item const& {
return items[id]; }

auto check_it_in_change_resistant_way() const
-> bool
{
auto const p_last_item = &items[Id::_ - 1];
for( auto p = &items[Id::a]; p != p_last_item; ++p )
{
if( *p > 0 ) { return true; }
}
return false;
}

auto check_it_directly() const
-> bool
{ return (items[0] || items[1] || items[2]); }
};
} // namespace my


Cheers & hth.,

- Alf

Jerry Stuckle

unread,
Aug 31, 2016, 11:17:24 PM8/31/16
to
Incorrect. Order of data members in the struct must be as they are
declared in the struct. There may be padding between the members, but
the order cannot change.

Compilers cannot "generate anything they want as long as the runs as
if". They are bound by other rules.

> So if you have a struct, and use things like the "offsetof" macro on its
> fields, the compiler is going to have to allocate members in the
> specified order. But if you have a "struct { int a; int b; }" used as a
> local variable without ever referring to their addresses, not only can
> the compiler swap a and b, but it can put them in registers, or even
> omit one of the members altogether if it can be "optimised away".
>
>

That is not the only reason compilers have to allocate members in the
specified order. Reading/writing binary files is another.

And the compilation of source file "A" has no idea if the compilation of
source file "B" uses any of the above. So even though "A" doesn't use
any of these features, the compiler cannot reorder members of a struct.

And the same is true in C.

--
==================
Remove the "x" from my email address
Jerry Stuckle
jstu...@attglobal.net
==================

David Brown

unread,
Sep 1, 2016, 3:07:39 AM9/1/16
to
On 31/08/16 22:52, Chris Vine wrote:
> On Wed, 31 Aug 2016 19:29:57 +0200
> David Brown <david...@hesbynett.no> wrote:
> [snip]
>> Apparently, you are not allowed to access the different parts of the
>> union as I had thought. My knowledge of such details in C++ is a
>> good deal less than my knowledge of C, and my knowledge of C has
>> holes too!
>
> It has undefined behaviour in C89, and C99 as originally printed. It
> has defined behaviour in C99 with Technical Corrigendum 3 applied and in
> C11, except that if there are padding bytes they can have a trap
> representation (§6.2.6.1/6 and /7 of C11 read with footnote 95 of
> §6.5.2.3/3 if you want the reference).

Yes, that's how I remember the standards. C90 standards did not allow
this sort of access to different parts of the union, but most
implementations did - and programmers relied on that as a way of
changing types without changing the underlying representation. So the
C99 (after the TC's) standard put it in.

But I guess C++ gets most of its C stuff from C90.

> The latter (trap
> representations) can be ignored on any architecture running C++.

Is that guaranteed by the C++ standards, or is it just that no one has
made a C++ compiler for one of the weird architectures that has trap
representations?

(In this particular case, the types in question were uint32_t and
uint64_t - these cannot have trap representations in C. But pointers,
signed integers, and floating point types could have trap
representations, in theory.)

> GCC
> and clang permit type punning through unions in C++ in the same way as
> an extension.

I believe the OP was using one of these (since he uses __attribute__).

>
> To make it portable I guess you could put the code in a separate
> translation unit compiled as C11 and link to that in your C++ code. It
> seems a bit overly complicated though.
>

Indeed. Sometimes it makes sense to use implementation-specific
behaviour (like "it works with gcc and clang"). But that's up to the OP
and his requirements.

> Chris
>

David Brown

unread,
Sep 1, 2016, 3:35:52 AM9/1/16
to
No, to a very large extent they /can/ generate anything they want - as
long as the code runs "as if" it followed the rules strictly. This is
one of the key points for an optimising compiler.

>
>> So if you have a struct, and use things like the "offsetof" macro on its
>> fields, the compiler is going to have to allocate members in the
>> specified order. But if you have a "struct { int a; int b; }" used as a
>> local variable without ever referring to their addresses, not only can
>> the compiler swap a and b, but it can put them in registers, or even
>> omit one of the members altogether if it can be "optimised away".
>>
>>
>
> That is not the only reason compilers have to allocate members in the
> specified order. Reading/writing binary files is another.

And how do you intend to read or write binary data between a file and a
struct, without taking the address of that struct? When you are doing
operations like that, the compiler must make sure the ordering of the
struct members follows the rules of the language (C or C++), and the ABI
requirements of the platform.

But when code does nothing (with defined behaviour) that could be
influenced by the ordering of the struct members, the compiler is free
to re-order those members. And with function-local data, it might well
do exactly that.

>
> And the compilation of source file "A" has no idea if the compilation of
> source file "B" uses any of the above. So even though "A" doesn't use
> any of these features, the compiler cannot reorder members of a struct.

The compiler can only re-order data if it can be sure it is safe to do
so - that is the same as for any optimisation. Since it does not know
what "B" will do with the data in "A", then typically it would not be
able to re-arrange the members. However, an implementation /could/ do
so - as long as it tracks this difference, such as via information in
the object file files, and ensures the complete result runs "as if" the
order was fixed. That's not going to happen in a compiler for big
systems, where object file formats follow known ABIs, but it is
perfectly allowed for specialised tools.

>
> And the same is true in C.
>

That, at least, is correct - the rules here for C and C++ are the same.

Öö Tiib

unread,
Sep 1, 2016, 4:29:01 AM9/1/16
to
On Thursday, 1 September 2016 03:29:35 UTC+3, Alf P. Steinbach wrote:
> On 31.08.2016 14:59, Melzzzzz wrote:
> > Code in question is like this:
> >
> > struct Problem{
> > uint32_t a;
> > uint32_t b;
> > uint64_t c;
> > uint32_t d;
> > bool check_it() {
> > for (uint32_t* i = &a;i != &d; ++i)
> > if (*i>0) return true;
> > return false;
> > }
> >
> > };
> >
> > I am not sure if this will work, so if someone has clear explanation
> > why it will work (or not) , I would be grateful.
>
> Formally there can be padding (except before the first item), and
> therefore formally you're in UB-land.
>
> And the formal UB means that an impractical compiler, a perverse
> compiler, can treat this as an opportunity to optimize away all of the
> checking. After all if it incurs UB, then in a correct program it would
> never be executed. So to the perverse compiler it's just dead code.
>
> But assuming a non-perverse compiler, you can simply
>
> static_assert( sizeof( Problem ) == 4*sizeof( uint32_t ) );

That assertion will fail on all platforms; it may be that you missed
the 'c' being 'uint64_t'.

Chris Vine

unread,
Sep 1, 2016, 7:30:53 AM9/1/16
to
On Thu, 01 Sep 2016 09:07:27 +0200
A trap representation is (according to C) "an object representation
that need not represent a value of the object type". §6.2.6.1/5 goes
on to say that "Certain object representations need not represent a
value of the object type. If the stored value of an object has such a
representation and is read by an lvalue expression that does not have
character type, the behavior is undefined. If such a representation is
produced by a side effect that modifies all or any part of the object
by an lvalue expression that does not have character type, the behavior
is undefined. Such a representation is called a trap representation".

The resulting undefined behaviour may include the triggering of hardware
traps.

C++ has not yet imported the "trap representation" from C: C++ instead
refers to uninitialised values of trivial types having "an
indeterminate value". In particular it does not so far permit access
to indeterminate values via the character types, but by the same token
I do not think that any architecture running C++ has hardware-level
traps for invalid signed arithmetic or floating points or for copying
invalid pointer values (but see below on pointers).

§8.5/12 of the draft C++17 standard sort-of introduces something similar
to the rules on trap representations by stating (in a convoluted
fashion) that if you evaluate an indeterminate value except via a
narrow unsigned character type you have undefined behaviour.

Since "evaluate" includes copy, this seems inconsistent with the
welcome licence given by §3.7.4.2/4 of C++14/17 which makes copying a
pointer value which is neither the null pointer nor the address of a
valid object implementation-defined behaviour instead of undefined
behaviour (C++14 tips it hat to C hardware traps by indicating that
that implementation-defined behaviour may include having "a
system-generated runtime fault"). No one yet seems to have spotted
this inconsistency.

Chris

Tim Rentsch

unread,
Sep 1, 2016, 12:01:21 PM9/1/16
to
Chris Vine <chris@cvine--nospam--.freeserve.co.uk> writes:

> On Wed, 31 Aug 2016 19:29:57 +0200
> David Brown <david...@hesbynett.no> wrote:
> [snip]
>> Apparently, you are not allowed to access the different parts of the
>> union as I had thought. My knowledge of such details in C++ is a
>> good deal less than my knowledge of C, and my knowledge of C has
>> holes too!
>
> It has undefined behaviour in C89, and C99 as originally printed. It
> has defined behaviour in C99 with Technical Corrigendum 3 applied and in
> C11, except that if there are padding bytes they can have a trap
> representation (section 6.2.6.1/6 and /7 of C11 read with footnote 95 of
> section 6.5.2.3/3 if you want the reference). [...]

I believe you are misreading or misremembering some of the various
C standards here. The behavior in C89 was implementation-defined,
not undefined. For section 6.2.6.1 p6 and p7, there is no
difference in the substance between C99 and C99-post-TC3, as it
relates to the example (for reference here is that code again):

struct Problem {
union {
struct {
uint32_t a;
uint32_t b;
uint64_t c;
uint32_t d;
}
uint32_t as_array[5];
}
// [.. original had a C++ member function ..]
}

It is true that if there are padding bytes between the members of
the inner struct those bytes may have unspecified values, but that
cannot cause undefined behavior for an access through 'as_array',
because the type uint32_t cannot have any trap representations.

As far as footnote 95 goes, footnotes are informative, not
normative; adding this footnote makes no difference to what is
defined behavior (although it may make that more obvious).
Moreover the notes of discussion regarding the footnote make it
clear that the point of adding it was just to be sure readers
would understand the semantics guaranteed under the original C99
standard (and effectively what was meant all along in C89, which
was phrased not as well as it might have been). The footnote
doesn't change anything; it just makes the existing semantics
more evident.

Tim Rentsch

unread,
Sep 1, 2016, 12:03:37 PM9/1/16
to
So this is another way that C++ is not upwards compatible from
C?

Chris Vine

unread,
Sep 1, 2016, 1:16:53 PM9/1/16
to
On Thu, 01 Sep 2016 09:01:10 -0700
Tim Rentsch <t...@alumni.caltech.edu> wrote:
> Chris Vine <chris@cvine--nospam--.freeserve.co.uk> writes:
>
> > On Wed, 31 Aug 2016 19:29:57 +0200
> > David Brown <david...@hesbynett.no> wrote:
> > [snip]
> >> Apparently, you are not allowed to access the different parts of
> >> the union as I had thought. My knowledge of such details in C++
> >> is a good deal less than my knowledge of C, and my knowledge of C
> >> has holes too!
> >
> > It has undefined behaviour in C89, and C99 as originally printed.
> > It has defined behaviour in C99 with Technical Corrigendum 3
> > applied and in C11, except that if there are padding bytes they can
> > have a trap representation (section 6.2.6.1/6 and /7 of C11 read
> > with footnote 95 of section 6.5.2.3/3 if you want the reference).
> > [...]
>
> I believe you are misreading or misremembering some of the various
> C standards here. The behavior in C89 was implementation-defined,
> not undefined. For section 6.2.6.1 p6 and p7, there is no
> difference in the substance between C99 and C99-post-TC3, as it
> relates to the example (for reference here is that code again):

On actually looking up §6.3.2.3 of C89/90 I concede you are right: it
is implementation-defined and not undefined. So much for memory. I
think you are also probably right about C99, given that footnotes are
not normative, although C99/11 gets awfully close to putting apparently
normative statements in footnotes.

> struct Problem {
> union {
> struct {
> uint32_t a;
> uint32_t b;
> uint64_t c;
> uint32_t d;
> }
> uint32_t as_array[5];
> }
> // [.. original had a C++ member function ..]
> }
>
> It is true that if there are padding bytes between the members of
> the inner struct those bytes may have unspecified values, but that
> cannot cause undefined behavior for an access through 'as_array',
> because the type uint32_t cannot have any trap representations.

I think you are wrong about that. §6.2.6.1/5, /6 and /7 read together
seem to me to be clear enough that if you type pun through a union where
the last value stored has padding, the bytes representing the padding
have an unspecified value which may be a trap representation if
actually read. You cannot get a trap representation from arithmetic
operations on valid values of unsigned integers, but that seems to me
to be a different matter. Integer values may have padding bits or
parity bits.

Chris

Jerry Stuckle

unread,
Sep 1, 2016, 3:34:23 PM9/1/16
to
They can "to a very large extent". But this does NOT include reordering
members of a struct. The most they can do is add padding between
members. That is not reordering.

>>
>>> So if you have a struct, and use things like the "offsetof" macro on its
>>> fields, the compiler is going to have to allocate members in the
>>> specified order. But if you have a "struct { int a; int b; }" used as a
>>> local variable without ever referring to their addresses, not only can
>>> the compiler swap a and b, but it can put them in registers, or even
>>> omit one of the members altogether if it can be "optimised away".
>>>
>>>
>>
>> That is not the only reason compilers have to allocate members in the
>> specified order. Reading/writing binary files is another.
>
> And how do you intend to read or write binary data between a file and a
> struct, without taking the address of that struct? When you are doing
> operations like that, the compiler must make sure the ordering of the
> struct members follows the rules of the language (C or C++), and the ABI
> requirements of the platform.
>

Taking the address of the struct is not the same as taking the address
of the members. You are not using offsetof(), for instance.

> But when code does nothing (with defined behaviour) that could be
> influenced by the ordering of the struct members, the compiler is free
> to re-order those members. And with function-local data, it might well
> do exactly that.
>

Incorrect (as you are incorrect when you claimed this in C): From the
standard, section 9.2, note 13:

"Nonstatic data members of a (non-union) class with the same access
control (Clause 11) are allocated so that later members have higher
addresses within a class object."

And don't get your panties in a wad over the use of the term "class".
The section is referring to classes, unions and structs.

>>
>> And the compilation of source file "A" has no idea if the compilation of
>> source file "B" uses any of the above. So even though "A" doesn't use
>> any of these features, the compiler cannot reorder members of a struct.
>
> The compiler can only re-order data if it can be sure it is safe to do
> so - that is the same as for any optimisation. Since it does not know
> what "B" will do with the data in "A", then typically it would not be
> able to re-arrange the members. However, an implementation /could/ do
> so - as long as it tracks this difference, such as via information in
> the object file files, and ensures the complete result runs "as if" the
> order was fixed. That's not going to happen in a compiler for big
> systems, where object file formats follow known ABIs, but it is
> perfectly allowed for specialised tools.
>

Not within a struct it cannot. See above.

>>
>> And the same is true in C.
>>
>
> That, at least, is correct - the rules here for C and C++ are the same.
>

Yup, the compiler can't do it in C, either.

David Brown

unread,
Sep 1, 2016, 4:45:12 PM9/1/16
to
In theory, yes. But the platforms that support C++ are much more
"normal" than those that support C, and there are far fewer C++
compilers around. If all these C++ compilers support type punning
through unions, as gcc and clang do, then there will be no
incompatibility in practice.

And perhaps someday someone will tidy up such missing points from the
C++ standards so that they catch up with the changes in later C standards.


me

unread,
Sep 1, 2016, 4:51:09 PM9/1/16
to
On Thursday, September 1, 2016 at 12:34:23 PM UTC-7, Jerry Stuckle wrote:
> On 9/1/2016 3:35 AM, David Brown wrote:
> > On 01/09/16 05:17, Jerry Stuckle wrote:

> >> Compilers cannot "generate anything they want as long as the runs as
> >> if". They are bound by other rules.
> >
> > No, to a very large extent they /can/ generate anything they want - as
> > long as the code runs "as if" it followed the rules strictly. This is
> > one of the key points for an optimising compiler.
> >
>
> They can "to a very large extent". But this does NOT include reordering
> members of a struct. The most they can do is add padding between
> members. That is not reordering.

Why do you think that structure member layout is immune to the as-if rule?

David Brown

unread,
Sep 1, 2016, 5:14:27 PM9/1/16
to
On 01/09/16 21:34, Jerry Stuckle wrote:
> On 9/1/2016 3:35 AM, David Brown wrote:
>> On 01/09/16 05:17, Jerry Stuckle wrote:

>>>
>>> Incorrect. Order of data members in the struct must be as they are
>>> declared in the struct. There may be padding between the members, but
>>> the order cannot change.
>>>
>>> Compilers cannot "generate anything they want as long as the runs as
>>> if". They are bound by other rules.
>>
>> No, to a very large extent they /can/ generate anything they want - as
>> long as the code runs "as if" it followed the rules strictly. This is
>> one of the key points for an optimising compiler.
>>
>
> They can "to a very large extent". But this does NOT include reordering
> members of a struct. The most they can do is add padding between
> members. That is not reordering.
>

Read up a bit about the "as if" rule.

You might also want to look up the "-fipa-struct-reorg" flag to gcc,
which existed between versions 4.4 and 4.8.

Here's a link so that you don't have to google:

<http://stackoverflow.com/questions/14671253/is-there-a-gcc-keyword-to-allow-structure-reordering>

And here's a paper discussing it on the Pathscale compiler:

<http://www.capsl.udel.edu/conferences/open64/2008/Papers/111.pdf>

Of course, it is conceivable that /you/ understand C and C++ far better
than the people writing these compilers - but I think it is unlikely.


Jerry Stuckle

unread,
Sep 1, 2016, 9:01:28 PM9/1/16
to
Because the standard says so. Read the entire message. It contains the
quote from the standard.

Jerry Stuckle

unread,
Sep 1, 2016, 9:02:47 PM9/1/16
to
And it is conceivable the quote I got from the standard shows how wrong
you are. But you never read that quote, did you?

Tim Rentsch

unread,
Sep 1, 2016, 9:08:56 PM9/1/16
to
IMO it is unacceptably bad practice to write code that depends
on this sort of untestable guarantee.

> And perhaps someday someone will tidy up such missing points from the
> C++ standards so that they catch up with the changes in later C
> standards.

At least in this area it looks like the departure is deliberate
and getting wider with time, not narrower.

Tim Rentsch

unread,
Sep 1, 2016, 9:37:58 PM9/1/16
to
Chris Vine <chris@cvine--nospam--.freeserve.co.uk> writes:

> On Thu, 01 Sep 2016 09:01:10 -0700
> Tim Rentsch <t...@alumni.caltech.edu> wrote:
>> Chris Vine <chris@cvine--nospam--.freeserve.co.uk> writes:
>>
>>> On Wed, 31 Aug 2016 19:29:57 +0200
>>> David Brown <david...@hesbynett.no> wrote:
>>> [snip]
>>>> Apparently, you are not allowed to access the different parts of
>>>> the union as I had thought. My knowledge of such details in C++
>>>> is a good deal less than my knowledge of C, and my knowledge of C
>>>> has holes too!
>>>
>>> It has undefined behaviour in C89, and C99 as originally printed.
>>> It has defined behaviour in C99 with Technical Corrigendum 3
>>> applied and in C11, except that if there are padding bytes they can
>>> have a trap representation (section 6.2.6.1/6 and /7 of C11 read
>>> with footnote 95 of section 6.5.2.3/3 if you want the reference).
>>> [...]
>>
>> I believe you are misreading or misremembering some of the various
>> C standards here. The behavior in C89 was implementation-defined,
>> not undefined. For section 6.2.6.1 p6 and p7, there is no
>> difference in the substance between C99 and C99-post-TC3, as it
>> relates to the example (for reference here is that code again):
>
> On actually looking up section 6.3.2.3 of C89/90 I concede you are
> right: it is implementation-defined and not undefined. So much
> for memory. I think you are also probably right about C99, given
> that footnotes are not normative, although C99/11 gets awfully
> close to putting apparently normative statements in footnotes.

Yes I think that does hold true for some footnotes. In the case
of this particular footnote, I have carefully gone through what
look like the relevant normative sections, and concluded that
there is in fact normative support for what the footnote says.
(I hasten to add the conclusion is nowhere near as obvious as I
would like.) So I think we are in agreement on this one.

>> struct Problem {
>> union {
>> struct {
>> uint32_t a;
>> uint32_t b;
>> uint64_t c;
>> uint32_t d;
>> }
>> uint32_t as_array[5];
>> }
>> // [.. original had a C++ member function ..]
>> }
>>
>> It is true that if there are padding bytes between the members of
>> the inner struct those bytes may have unspecified values, but that
>> cannot cause undefined behavior for an access through 'as_array',
>> because the type uint32_t cannot have any trap representations.
>
> I think you are wrong about that. Sections 6.2.6.1/5, /6 and /7
> read together seem to me to be clear enough that if you type pun
> through a union where the last value stored has padding, the bytes
> representing the padding have an unspecified value

I agree with you on that, in particular for the case where the
other member in question being a struct, which is the case here.

> which may be a
> trap representation if actually read.

Again I agree, although it depends on the type used to do the
reading.

> You cannot get a trap
> representation from arithmetic operations on valid values of
> unsigned integers, but that seems to me to be a different matter.
> Integer values may have padding bits or parity bits.

That is true for integer types generally, but the fixed-width
types like uint32_t have additional guarantees that preclude the
possibility of padding bits or trap representations. You might
want to look that up in the section for <stdint.h>. The lack of
trap representations for uint32_t forms the crux of my argument.
(Probably I should have mentioned the more stringent guarantees
for these fixed-width types before, but 20-20 hindsight and all
that...)

me

unread,
Sep 1, 2016, 10:03:07 PM9/1/16
to
On Thursday, September 1, 2016 at 6:01:28 PM UTC-7, Jerry Stuckle wrote:
> On 9/1/2016 4:50 PM, me wrote:
> > On Thursday, September 1, 2016 at 12:34:23 PM UTC-7, Jerry Stuckle wrote:
> >> On 9/1/2016 3:35 AM, David Brown wrote:
> >>> On 01/09/16 05:17, Jerry Stuckle wrote:
> >
> >>>> Compilers cannot "generate anything they want as long as the runs as
> >>>> if". They are bound by other rules.
> >>>
> >>> No, to a very large extent they /can/ generate anything they want - as
> >>> long as the code runs "as if" it followed the rules strictly. This is
> >>> one of the key points for an optimising compiler.
> >>>
> >>
> >> They can "to a very large extent". But this does NOT include reordering
> >> members of a struct. The most they can do is add padding between
> >> members. That is not reordering.
> >
> > Why do you think that structure member layout is immune to the as-if rule?
> >
>
> Because the standard says so. Read the entire message. It contains the
> quote from the standard.
>

I did.

The standard also says that the as-if rule over-rides everything else in
the standard, and that only observable behaviour of the program need be
considered. So again, why is structure member layout _different_ in this
respect? There are all sorts of things that I could quote from the standard,
specifying how the abstract machine must do things, but none of which matter
one jot as long as the program produces the output specified.

Given these two programs:
<program 1>
#include <cstdio>
struct S { int a; int b; };
struct S s = { 1, 2 };
int main(void){ printf("%d\n", s.a); return 0; }
</program 1>
and
<program 2>
#include <cstdio>
struct S { int b; int a; };
struct S s = { 2, 1 };
int main(void) { printf("%d\n", s.a); return 0; }
<program 2>

If a compiler produced exactly, bit-for-bit, the same executable for
these two programs, would you complain to the vendor that they were
disobeying 9.2.13? What would you say to convince them that the as-if
rule _didn't_ apply?

Jerry Stuckle

unread,
Sep 1, 2016, 10:17:16 PM9/1/16
to
On 9/1/2016 10:02 PM, me wrote:
> On Thursday, September 1, 2016 at 6:01:28 PM UTC-7, Jerry Stuckle wrote:
>> On 9/1/2016 4:50 PM, me wrote:
>>> On Thursday, September 1, 2016 at 12:34:23 PM UTC-7, Jerry Stuckle wrote:
>>>> On 9/1/2016 3:35 AM, David Brown wrote:
>>>>> On 01/09/16 05:17, Jerry Stuckle wrote:
>>>
>>>>>> Compilers cannot "generate anything they want as long as the runs as
>>>>>> if". They are bound by other rules.
>>>>>
>>>>> No, to a very large extent they /can/ generate anything they want - as
>>>>> long as the code runs "as if" it followed the rules strictly. This is
>>>>> one of the key points for an optimising compiler.
>>>>>
>>>>
>>>> They can "to a very large extent". But this does NOT include reordering
>>>> members of a struct. The most they can do is add padding between
>>>> members. That is not reordering.
>>>
>>> Why do you think that structure member layout is immune to the as-if rule?
>>>
>>
>> Because the standard says so. Read the entire message. It contains the
>> quote from the standard.
>>
>
> I did.
>
> The standard also says that the as-if rule over-rides everything else in
> the standard, and that only observable behaviour of the program need be
> considered. So again, why is structure member layout _different_ in this
> respect? There are all sorts of things that I could quote from the standard,
> specifying how the abstract machine must do things, but none of which matter
> one jot as long as the program produces the output specified.
>

And where does it say the rule can override such structures? You are
misreading the standard. The as-if rule applies to execution, not
memory layout.

> Given these two programs:
> <program 1>
> #include <cstdio>
> struct S { int a; int b; };
> struct S s = { 1, 2 };
> int main(void){ printf("%d\n", s.a); return 0; }
> </program 1>
> and
> <program 2>
> #include <cstdio>
> struct S { int b; int a; };
> struct S s = { 2, 1 };
> int main(void) { printf("%d\n", s.a); return 0; }
> <program 2>
>
> If a compiler produced exactly, bit-for-bit, the same executable for
> these two programs, would you complain to the vendor that they were
> disobeying 9.2.13? What would you say to convince them that the as-if
> rule _didn't_ apply?
>

Yes, because they are. What would YOU say to convince someone it is OK?

If your interpretation were correct, there would be no need for 9.2.13.
But it's there - so there must be a reason. Maybe it's because you
don't understand the as-if rule.

David Brown

unread,
Sep 2, 2016, 3:24:30 AM9/2/16
to
That is certainly true for some types of code. But a great deal of code
does not need wide portability. If I am writing code that will run on a
particular target, compiled with a particular toolchain, it is bad
practice to write widely portable code if knowledge of the target and
toolchain could mean cleaner, clearer, safer and more efficient code.
Assumptions should be well documented, preferably with compile-time
checking, but it is perfectly acceptable to rely on implementation
defined behaviour. If I am writing a driver for the ADC on a
microcontroller, I refuse to write some memcpy monstrosity just in case
someone wants to compile the code on a PDP-9. And if gcc extensions let
me make the code better, then I will use gcc extensions - and you can't
use the same code with Keil or IAR's compilers.

But of course this sort of thing will vary depending on the type of
programming you do. /I/ can work this way. When I put together a
project, the toolchain (compiler, linker scripts, libraries, etc.) is
part of the project, and archived with it. I can pull up 20 year old
projects, do a clean make, and get bit-identical binary outputs (yes,
I've done that).

However, if you are writing some library functions that may be used on
many different systems - including those in the future - then you have
very different requirements and restrictions in the way you code.

David Brown

unread,
Sep 2, 2016, 3:35:53 AM9/2/16
to
Yes, I read the quotation. And note here that I referenced compiler
writers opinions on applying the as-if rule to struct layout - not just
my own. Are you telling me that you know better than they do?

And I see from your other posts that you believe "the as-if rule applies
to execution, not memory layout". If that belief were true, then you
would be correct that struct layout is exempt from as-if optimisation.
However, it is /not/ true.

There are two reasons for me saying this. First, there is nowhere in
the standards (C standards at least - I haven't read as much of the C++
standards) that makes this distinction.

Secondly, as long as we are talking about memory that can only be seen
from within the program (while following the rules of C), memory layout
is nothing more than an effect of execution. The way a struct is laid
out is not observable behaviour in itself, and thus the compiler is free
to change it.

It is /not/ free to change struct layout when that data is passed to
external functions, written to files, or has volatile behaviour - those
are observable effects. But if the data stays within the program as
known to the compiler, the compiler is free to do as it wants.




Manfred

unread,
Sep 2, 2016, 5:41:15 AM9/2/16
to
On 9/2/2016 4:02 AM, me wrote:
>
> I did.
>
> The standard also says that the as-if rule over-rides everything else in
> the standard, and that only observable behaviour of the program need be
> considered. So again, why is structure member layout _different_ in this
> respect?
>
It is different because of the presence of the union.
When you access the struct memory area through the array you are
accessing data in a well-specified order, and the struct members must
therefore follow the order specified by the standard.
As long as memory access is legal, and it is in this case, if
optimization could reorder the struct members, the "as-if" rule would be
violated because the optimized and non-optimized code results would be
different.

I may think the union+array trick also solves the problem of
interleaving of data members with different access control, and "space
for managing virtual functions and virtual base classes" (also from the
same clause of the standard), because the union becomes its own data
item within "struct Problem", encapsulated with no other data and no
virtual members or bases.
But someone else may be more specific than I can be on this.

Chris Vine

unread,
Sep 2, 2016, 5:42:55 AM9/2/16
to
On Thu, 01 Sep 2016 18:37:47 -0700
OK that's good to know. The thesis in my original post on this was
that if you compile the type-punning code as C99 or C11 and link to it
in your C++ code it would work, because no architectures in fact running
C++ have trap representations on integers in C. You are, like Judge
Dredd, saying that it will work because it _is_ the law, for fixed size
unsigned integers at least.

Apropos of which, and moving on from indeterminate values arising from
padding to indeterminate values arising from uninitialized built-in
types, C appears to do this much better than the proposal in what is
now §8.6/12 of N4606 for C++. C seems to provide that an uninitialised
variable may hold a trap representation, but it may equally well have a
valid (unknown) value in it, which is in fact what will happen on 99%
or architectures and all those running C++. For the latter, these can
be evaluated, say by copying. §8.6/12 of N4606 on the other hand
provides for blanket undefined behaviour for any copying or other
evaluation of an uninitialized object of built-in type which is not an
unsigned narrow character (unsigned char, and char where char is
unsigned).

I don't like the way C++ sprays around undefined behaviour at the
slightest provocation. Unions are another example.

Chris

David Brown

unread,
Sep 2, 2016, 6:27:30 AM9/2/16
to
On 02/09/16 11:41, Manfred wrote:
> On 9/2/2016 4:02 AM, me wrote:
>>
>> I did.
>>
>> The standard also says that the as-if rule over-rides everything else in
>> the standard, and that only observable behaviour of the program need be
>> considered. So again, why is structure member layout _different_ in this
>> respect?
>>
> It is different because of the presence of the union.
> When you access the struct memory area through the array you are
> accessing data in a well-specified order, and the struct members must
> therefore follow the order specified by the standard.
> As long as memory access is legal, and it is in this case, if
> optimization could reorder the struct members, the "as-if" rule would be
> violated because the optimized and non-optimized code results would be
> different.

The as-if rule still applies. If we stick to C, where you /are/ allowed
to access data in different ways with a union, we could have this:

union {
struct {
uint32_t a;
uint32_t b;
uint64_t c;
uint32_t d;
};
uint32_t as_array[5];
} u;

When you write:

uint32_t foo(void) {
u.d = 123;
u.b = u.as_array[4];
return u.as_array[1];
}

The compiler will have to return 123. It must /behave/ in this way.
But it does /not/ have to keep the struct in the order you have given -
it is allowed to transform that program into this:

union {
struct {
uint64_t c; // <- Note the change
uint32_t a;
uint32_t b;
uint32_t d;
};
uint32_t as_array[5];
} u;

uint32_t foo(void) {
u.d = 123;
u.b = u.as_array[4];
return u.as_array[3]; // <- Note the change
}


Would a compiler actually do this? No, it is highly unlikely - it's
just too much effort to get it all correct, and too little gain. But it
/is/ legal, by the "as-if" rule.

And there /are/ compilers that re-arrange structs - they might be
reducing padding, improving cache line hits, separating "hot" and "cold"
parts, removing unused fields, etc. When the structs are used in a
simple manner, that will be fine - when they are used in other ways
(such as with a union, or memcpy'ing, or taking addresses of members),
there quickly becomes a point where it is too difficult to track for
correctness if the struct is re-arranged.


>
> I may think the union+array trick also solves the problem of
> interleaving of data members with different access control, and "space
> for managing virtual functions and virtual base classes" (also from the
> same clause of the standard), because the union becomes its own data
> item within "struct Problem", encapsulated with no other data and no
> virtual members or bases.
> But someone else may be more specific than I can be on this.
>

Maybe it is precisely to avoid that sort of access control cheating that
C++ makes such union+array tricks undefined behaviour.

Ben Bacarisse

unread,
Sep 2, 2016, 7:37:33 AM9/2/16
to
David Brown <david...@hesbynett.no> writes:

> On 02/09/16 11:41, Manfred wrote:
>> On 9/2/2016 4:02 AM, me wrote:
<snip>
>>> The standard also says that the as-if rule over-rides everything else in
>>> the standard, and that only observable behaviour of the program need be
>>> considered. So again, why is structure member layout _different_ in this
>>> respect?
>>>
>> It is different because of the presence of the union.
>> When you access the struct memory area through the array you are
>> accessing data in a well-specified order, and the struct members must
>> therefore follow the order specified by the standard.
>> As long as memory access is legal, and it is in this case, if
>> optimization could reorder the struct members, the "as-if" rule would be
>> violated because the optimized and non-optimized code results would be
>> different.
>
> The as-if rule still applies. If we stick to C, where you /are/ allowed
> to access data in different ways with a union, we could have this:
>
> union {
> struct {
> uint32_t a;
> uint32_t b;
> uint64_t c;
> uint32_t d;
> };
> uint32_t as_array[5];
> } u;

Is the 5 a typo?

> When you write:
>
> uint32_t foo(void) {
> u.d = 123;
> u.b = u.as_array[4];
> return u.as_array[1];
> }

Is the 4 a typo?

> The compiler will have to return 123. It must /behave/ in this way.

I've not been following the details, so maybe there are some assumptions
in play here, but if the struct has unknown padding the only thing you
can rely on is that u.a and u.as_array[0] overlap.

<snip>
--
Ben.

Richard Damon

unread,
Sep 2, 2016, 8:04:12 AM9/2/16
to
No it does not. a must match as_array[0] but the compiler is allowed to
insert padding between a and b. (Yes, for most machines it is unlikely
to, but it can). One motivation would be if you had a machine that was
naturally faster accessing 64 bit aligned objects than 32, but could
access 32 bit objects (perhaps with multiple instructions). An example
would be a 64 bit word based machine that natively only could access at
at 64 bit level, but to look like a more conventional machine the
compiler simulated smaller accesses (to avoid having CHAR_BIT == 64 and
sizeof(long long) == 1 which would give many programs problems, not
unlike the 16 bit access machine of yesteryear). On such a machine, b
would be at as_array[2], not [1] as expected, and [1] would map to a
padding word.

Jerry Stuckle

unread,
Sep 2, 2016, 8:50:12 AM9/2/16
to
The as-if rule applies to execution. If it applied here, 9.2.13 would
be meaningless.

> And I see from your other posts that you believe "the as-if rule applies
> to execution, not memory layout". If that belief were true, then you
> would be correct that struct layout is exempt from as-if optimisation.
> However, it is /not/ true.
>

Once again you are incorrect.

> There are two reasons for me saying this. First, there is nowhere in
> the standards (C standards at least - I haven't read as much of the C++
> standards) that makes this distinction.
>

Again you are incorrect. The same rule applies to C.

> Secondly, as long as we are talking about memory that can only be seen
> from within the program (while following the rules of C), memory layout
> is nothing more than an effect of execution. The way a struct is laid
> out is not observable behaviour in itself, and thus the compiler is free
> to change it.
>

The struct layout is observable behavior, and cannot be changed. 9.2.13
says so.

> It is /not/ free to change struct layout when that data is passed to
> external functions, written to files, or has volatile behaviour - those
> are observable effects. But if the data stays within the program as
> known to the compiler, the compiler is free to do as it wants.
>

Sorry, you are once again wrong. The compiler doesn't know what a
function does. You are really grasping at straws now, David.

Just admit you are wrong and move on. Or explain why 9.2.13 exists,
when according to you, it is meaningless.

BartC

unread,
Sep 2, 2016, 8:52:15 AM9/2/16
to
Easy to fix:

#pragma pack(1) // or better, push then later pop

union {
struct {
uint32_t a;
uint32_t b;
etc.

--
Bartc

Manfred

unread,
Sep 2, 2016, 9:17:49 AM9/2/16
to
You mean that the compiler would be allowed to rearrange the entire
address space (variables /and/ addresses: the programmer asks for
u.as_array[1] and gets u.as_array[3]) so that they appear to be in order
while physically they are not. I strongly doubt this, simply because it
would be almost impossible to guarantee the expected results for any
generic input code (and it would often provide no performance change or
even a degradation). Note that in your example the compiler designer
would have to build in the knowledge that the return value of foo is u.b
instead of u.as_array[1], which is true for your specific example only.



On the other hand, even if such obscure behaviour occurred, it would be
completely transparent to the programmer, so that it could be ignored
anyway.



To put it more simple:



#include <cstdio>
#include <cstdint>

union {
struct __attribute__ ((__packed__)) {
uint32_t a;
uint32_t b;
uint64_t c;
uint32_t d;
};
uint32_t as_array[5];
} u;

void foo(void) {
u.a = 1;
u.b = 2;
u.c = 3;
u.d = 4;
}

void bar(void) {
for(uint32_t* p = u.as_array; p < u.as_array+5; ++p) {
printf("%u\n", *p);
}
}

int main(void) {
foo();
bar();
}

The output must be
1
2
3
0
4
(assuming little endian), and since we are scanning the memory area
sequentially, variables must be ordered as coded. Again, even if obscure
things would be allowed to happen, they would be transparent to the
programmer, so that they could be ignored.


me

unread,
Sep 2, 2016, 11:20:07 AM9/2/16
to
Have _you_ read 1.9.1? "[C]onforming implementations are required to
emulate (only) the observable behavior of the abstract machine as explained
below." Since 9.2.13 .gt. 1.9, clearly it applies to structure member
layout.

> > Given these two programs:
> > <program 1>
> > #include <cstdio>
> > struct S { int a; int b; };
> > struct S s = { 1, 2 };
> > int main(void){ printf("%d\n", s.a); return 0; }
> > </program 1>
> > and
> > <program 2>
> > #include <cstdio>
> > struct S { int b; int a; };
> > struct S s = { 2, 1 };
> > int main(void) { printf("%d\n", s.a); return 0; }
> > <program 2>
> >
> > If a compiler produced exactly, bit-for-bit, the same executable for
> > these two programs, would you complain to the vendor that they were
> > disobeying 9.2.13? What would you say to convince them that the as-if
> > rule _didn't_ apply?
> >
>
> Yes, because they are. What would YOU say to convince someone it is OK?

My first recourse of course would be to reference 1.9.1. But maybe a
simpler approach would just be "Prove it". I.e., prove that in program 1
the memory address of s.a is higher than s.b, OR prove that in program 2
the memory address of s.a is lower than s.b.

>
> If your interpretation were correct, there would be no need for 9.2.13.
> But it's there - so there must be a reason. Maybe it's because you
> don't understand the as-if rule.

Of course it's still needed. It describes certain observable behaviour,
like taking addresses and offsets of struct members. But in the absence
of taking those addresses, I really can't understand how "behaviour"
that is _completely_unobservable_ via standards-mandated means, could
possibly be construed as "observable behaviour".

David Brown

unread,
Sep 2, 2016, 11:39:31 AM9/2/16
to
No - "c" is a uint64_t, while the others are uint32_t. I don't know if
that was a typo in the OP's first post, but I've followed it.

>
>> When you write:
>>
>> uint32_t foo(void) {
>> u.d = 123;
>> u.b = u.as_array[4];
>> return u.as_array[1];
>> }
>
> Is the 4 a typo?
>
>> The compiler will have to return 123. It must /behave/ in this way.
>
> I've not been following the details, so maybe there are some assumptions
> in play here, but if the struct has unknown padding the only thing you
> can rely on is that u.a and u.as_array[0] overlap.
>

It's true that there could be padding here - my assumption is that there
is no padding.

But the point still stands - /if/ the first code is allowed (depending
on implementation-dependent padding), then the second code is an
allowable transformation by the compiler.

> <snip>
>

Melzzzzz

unread,
Sep 2, 2016, 11:40:23 AM9/2/16
to
It was not typo. I only missed to say that struct has packed attribute.

David Brown

unread,
Sep 2, 2016, 11:46:45 AM9/2/16
to
The point is that the output you have shown here is observable
behaviour. In this case, it is the /only/ observable behaviour. And
the compiler is free to make whatever transformations it wants, as long
as the observable behaviour matches. The compiler is therefore free to
re-arrange the structs as it wants - just as it is free to turn main() into

int main(void) {
puts("1\n2\n3\n0\n4\n");
}

Of course, that would only be legal if the compiler knew that the code
would not be statically linked with other code that called foo, bar, or
main, or used u. When gcc had an option for re-ordering structs, it
could only be enabled along with the "-fwhole-program" flag for
precisely that reason. But if the relevant structs and functions had
been locals or file static (with no "escapes"), then the compiler could
freely transform it.


Ben Bacarisse

unread,
Sep 2, 2016, 11:54:15 AM9/2/16
to
Ah, right. I missed that.

<snip>
>> I've not been following the details, so maybe there are some assumptions
>> in play here, but if the struct has unknown padding the only thing you
>> can rely on is that u.a and u.as_array[0] overlap.
>>
>
> It's true that there could be padding here - my assumption is that there
> is no padding.

I'd missed that too.

<snip>
--
Ben.

David Brown

unread,
Sep 2, 2016, 11:59:55 AM9/2/16
to
No, it would not be meaningless - it is as meaningful as the rest of the
standard. The as-if rule says that could must produce observable
behaviour as though it slavishly followed the standard - including
9.2.13. As long as the program produces the same observable behaviour,
it can rearrange structs as it wants - just as it can make optimisations
that appear to contradict any other rules. There is nothing special
about 9.2.13 in this regard.

Now, you failed to answer my question - are /you/ claiming to understand
the standards better than the people who wrote the Pathscale compiler
and the people who wrote gcc?

>
>> And I see from your other posts that you believe "the as-if rule applies
>> to execution, not memory layout". If that belief were true, then you
>> would be correct that struct layout is exempt from as-if optimisation.
>> However, it is /not/ true.
>>
>
> Once again you are incorrect.
>
>> There are two reasons for me saying this. First, there is nowhere in
>> the standards (C standards at least - I haven't read as much of the C++
>> standards) that makes this distinction.
>>
>
> Again you are incorrect. The same rule applies to C.

I am happy to believe that the same rule applies here in C and C++. It
is simply not the rule that you think it is.

>
>> Secondly, as long as we are talking about memory that can only be seen
>> from within the program (while following the rules of C), memory layout
>> is nothing more than an effect of execution. The way a struct is laid
>> out is not observable behaviour in itself, and thus the compiler is free
>> to change it.
>>
>
> The struct layout is observable behavior, and cannot be changed. 9.2.13
> says so.

No, 9.2.13 says nothing about observable behaviour. Read it again, and
see if you spot that phrase. And in the definition of observable
behaviour (section 1.9.8), no mention is made of struct layout or memory
(except in regard to volatile accesses).

You are simply wrong here. You are making things up that are not in the
standards.

>
>> It is /not/ free to change struct layout when that data is passed to
>> external functions, written to files, or has volatile behaviour - those
>> are observable effects. But if the data stays within the program as
>> known to the compiler, the compiler is free to do as it wants.
>>
>
> Sorry, you are once again wrong. The compiler doesn't know what a
> function does. You are really grasping at straws now, David.

If the compiler does not know what a function does (such as for external
functions), then it must assume the worst - it must assume it has
volatile accesses to all globally visible data, for example, and thus
any such data must follow the rules for struct layout. But it can
assume that the external function has defined behaviour - and thus
cannot read local data or file static data that has not escaped in some
way, and it can re-arrange such data as it likes.

And if the compiler knows the definition of the function, then it will
know which re-arrangements and optimisations are safe. With
whole-program or link-time optimisation, the compiler may even know the
definitions of every function in the program.

>
> Just admit you are wrong and move on. Or explain why 9.2.13 exists,
> when according to you, it is meaningless.
>

No, only you have claimed it is meaningless. I am quite happy with its
meaning.

Jerry Stuckle

unread,
Sep 2, 2016, 12:39:15 PM9/2/16
to
Yes, and "below" refers to the rest of section 1.9, NOT the entire rest
of the standard.

Additionally, 1.9 refers to "Program Execution". Not memory layout.

>>> Given these two programs:
>>> <program 1>
>>> #include <cstdio>
>>> struct S { int a; int b; };
>>> struct S s = { 1, 2 };
>>> int main(void){ printf("%d\n", s.a); return 0; }
>>> </program 1>
>>> and
>>> <program 2>
>>> #include <cstdio>
>>> struct S { int b; int a; };
>>> struct S s = { 2, 1 };
>>> int main(void) { printf("%d\n", s.a); return 0; }
>>> <program 2>
>>>
>>> If a compiler produced exactly, bit-for-bit, the same executable for
>>> these two programs, would you complain to the vendor that they were
>>> disobeying 9.2.13? What would you say to convince them that the as-if
>>> rule _didn't_ apply?
>>>
>>
>> Yes, because they are. What would YOU say to convince someone it is OK?
>
> My first recourse of course would be to reference 1.9.1. But maybe a
> simpler approach would just be "Prove it". I.e., prove that in program 1
> the memory address of s.a is higher than s.b, OR prove that in program 2
> the memory address of s.a is lower than s.b.
>

And once again you are reading the standard wrong.

>>
>> If your interpretation were correct, there would be no need for 9.2.13.
>> But it's there - so there must be a reason. Maybe it's because you
>> don't understand the as-if rule.
>
> Of course it's still needed. It describes certain observable behaviour,
> like taking addresses and offsets of struct members. But in the absence
> of taking those addresses, I really can't understand how "behaviour"
> that is _completely_unobservable_ via standards-mandated means, could
> possibly be construed as "observable behaviour".
>

Why is it still needed? It describes no behavior. It describes memory
layout - which you just said is overridden by 1.9.1.

Jerry Stuckle

unread,
Sep 2, 2016, 12:49:16 PM9/2/16
to
No, you are making up things which are not what the standard says. No,
section 1.9.8 doesn't say anything about struct layout. That is not its
purpose.

And 1.9.1 refers to the remainder of section 1.9, not the entire
standard. Plus, 1.9 refers to program execution - not memory layout.
Layout is not behavior.

1.9.1 is for things like the following:

a = 2;
b = 3;
c = 2;

Can be reordered to

a = c = 2;
b = 3;

Of course it's more than that. But to stay in line with what you can
understand, I'm keeping it simple.

>>
>>> It is /not/ free to change struct layout when that data is passed to
>>> external functions, written to files, or has volatile behaviour - those
>>> are observable effects. But if the data stays within the program as
>>> known to the compiler, the compiler is free to do as it wants.
>>>
>>
>> Sorry, you are once again wrong. The compiler doesn't know what a
>> function does. You are really grasping at straws now, David.
>
> If the compiler does not know what a function does (such as for external
> functions), then it must assume the worst - it must assume it has
> volatile accesses to all globally visible data, for example, and thus
> any such data must follow the rules for struct layout. But it can
> assume that the external function has defined behaviour - and thus
> cannot read local data or file static data that has not escaped in some
> way, and it can re-arrange such data as it likes.
>

And how is the compiler to know that? Does it predict the future?

struct mystruc {
int a, b;
};

func f() }
struct mystruct ms;
ms.a = 1; // The structure has been defined
ms.b = 2;
write(ms); // NOW the compiler knows that there is a call
}

It is a one-pass compiler. There is no way for it to know when
assigning ms.a that there is going to be a call to another function.


> And if the compiler knows the definition of the function, then it will
> know which re-arrangements and optimisations are safe. With
> whole-program or link-time optimisation, the compiler may even know the
> definitions of every function in the program.
>

Not before the structure has been defined.

>>
>> Just admit you are wrong and move on. Or explain why 9.2.13 exists,
>> when according to you, it is meaningless.
>>
>
> No, only you have claimed it is meaningless. I am quite happy with its
> meaning.
>

No, you said the compiler is free to reorder the memory. That is in
direct conflict with 9.2.13. So it is you who declare it meaningless.

You are just digging yourself a deeper and deeper hole,

David Brown

unread,
Sep 2, 2016, 2:22:27 PM9/2/16
to
I can't really blame you for not noticing my unstated assumptions -
especially as they were based on the OP's omitted "packed" attribute :-)

I'd be surprised if there are any implementations of C that would put
padding in this struct even without a "packed" attribute - it would
almost have to be an architecture with 64-bit int and 32-bit short for
packing to make much sense. But it was still an assumption, and should
have been stated.


David Brown

unread,
Sep 2, 2016, 2:37:09 PM9/2/16
to
On 02/09/16 18:49, Jerry Stuckle wrote:
> On 9/2/2016 11:59 AM, David Brown wrote:
>> On 02/09/16 14:50, Jerry Stuckle wrote:
>>> On 9/2/2016 3:35 AM, David Brown wrote:
>>>> On 02/09/16 03:02, Jerry Stuckle wrote:

<snip>

>>>> Secondly, as long as we are talking about memory that can only be seen
>>>> from within the program (while following the rules of C), memory layout
>>>> is nothing more than an effect of execution. The way a struct is laid
>>>> out is not observable behaviour in itself, and thus the compiler is free
>>>> to change it.
>>>>
>>>
>>> The struct layout is observable behavior, and cannot be changed. 9.2.13
>>> says so.
>>
>> No, 9.2.13 says nothing about observable behaviour. Read it again, and
>> see if you spot that phrase. And in the definition of observable
>> behaviour (section 1.9.8), no mention is made of struct layout or memory
>> (except in regard to volatile accesses).
>>
>> You are simply wrong here. You are making things up that are not in the
>> standards.
>>
>
> No, you are making up things which are not what the standard says. No,
> section 1.9.8 doesn't say anything about struct layout. That is not its
> purpose.
>

I did not say that 1.9.8 discussed the layout of structs - I said it did
/not/ cover struct layout.

> And 1.9.1 refers to the remainder of section 1.9, not the entire
> standard. Plus, 1.9 refers to program execution - not memory layout.
> Layout is not behavior.

1.9.1 refers to the observable behaviour, which is defined "below" in
1.9.8. Section 1.9.8 refers to the entire rest of the standard.

And memory layout is behaviour.

>
> 1.9.1 is for things like the following:
>
> a = 2;
> b = 3;
> c = 2;
>
> Can be reordered to
>
> a = c = 2;
> b = 3;
>
> Of course it's more than that. But to stay in line with what you can
> understand, I'm keeping it simple.

It covers /vastly/ more than that. It is the basis for the concept of
an "optimising compiler".

>
>>>
>>>> It is /not/ free to change struct layout when that data is passed to
>>>> external functions, written to files, or has volatile behaviour - those
>>>> are observable effects. But if the data stays within the program as
>>>> known to the compiler, the compiler is free to do as it wants.
>>>>
>>>
>>> Sorry, you are once again wrong. The compiler doesn't know what a
>>> function does. You are really grasping at straws now, David.
>>
>> If the compiler does not know what a function does (such as for external
>> functions), then it must assume the worst - it must assume it has
>> volatile accesses to all globally visible data, for example, and thus
>> any such data must follow the rules for struct layout. But it can
>> assume that the external function has defined behaviour - and thus
>> cannot read local data or file static data that has not escaped in some
>> way, and it can re-arrange such data as it likes.
>>
>
> And how is the compiler to know that? Does it predict the future?
>
> struct mystruc {
> int a, b;
> };
>
> func f() }
> struct mystruct ms;
> ms.a = 1; // The structure has been defined
> ms.b = 2;
> write(ms); // NOW the compiler knows that there is a call
> }
>
> It is a one-pass compiler. There is no way for it to know when
> assigning ms.a that there is going to be a call to another function.
>

That was perhaps true in the days when compilers read programs on
punched cards. But these days, compilers are smarter than that. Before
the compiler generates anything for "ms.a", it has already parsed all
the rest of the file - and perhaps all the other files in the program.

Perhaps you use a one-pass compiler, with all its limitations. I don't
know how many passes modern gcc or clang have, but according to a quick
google gcc 4.6.2 had 207 unique passes.


>
>> And if the compiler knows the definition of the function, then it will
>> know which re-arrangements and optimisations are safe. With
>> whole-program or link-time optimisation, the compiler may even know the
>> definitions of every function in the program.
>>
>
> Not before the structure has been defined.

The compiler collects all the information about the program, data,
structures, functions, etc., before it starts organising the data or
generating the code. That's the point of whole-program optimisation.

>
>>>
>>> Just admit you are wrong and move on. Or explain why 9.2.13 exists,
>>> when according to you, it is meaningless.
>>>
>>
>> No, only you have claimed it is meaningless. I am quite happy with its
>> meaning.
>>
>
> No, you said the compiler is free to reorder the memory. That is in
> direct conflict with 9.2.13. So it is you who declare it meaningless.

Yes, the compiler is free to re-order anything it likes - code,
functions, memory, structs, whatever - as long as the observable
behaviour is unchanged.

>
> You are just digging yourself a deeper and deeper hole,
>

You simply don't understand much about how compilers work. That's okay,
you don't have to know how they work in order to use them. But you do
look silly by continuing to flaunt your ignorance.

But keep going, if you like - it is somewhat entertaining. The idea
that a modern C compiler is one-pass and generates the code for one line
of source before reading the next line gave me a bit of a chuckle.

Chris M. Thomasson

unread,
Sep 2, 2016, 3:07:03 PM9/2/16
to
On 8/31/2016 5:28 PM, Alf P. Steinbach wrote:
> On 31.08.2016 14:59, Melzzzzz wrote:
>> Code in question is like this:
>>
>> struct Problem{
>> uint32_t a;
>> uint32_t b;
>> uint64_t c;
>> uint32_t d;
>> bool check_it() {
>> for (uint32_t* i = &a;i != &d; ++i)
>> if (*i>0) return true;
>> return false;
>> }
>>
>> };
>>
>> I am not sure if this will work, so if someone has clear explanation
>> why it will work (or not) , I would be grateful.
>
> Formally there can be padding (except before the first item), and
> therefore formally you're in UB-land.

[...]

Right. So, this little program below should have no undefined behavior:
________________________________________________
#include <cstddef>
#include <cstdio>

struct A
{
int v;
};

struct B
{
A m_a0;
char c;
A m_a1;
};

int main()
{
B b = { { 0 }, 'c', { 1 } };
A* pa0 = &b.m_a0;
B* bp = reinterpret_cast<B*>(pa0);

unsigned char* a = reinterpret_cast<unsigned char*>(bp);

char* pc = reinterpret_cast<char*>(a + offsetof(B, c));
A* pa1 = reinterpret_cast<A*>(a + offsetof(B, m_a1));

pa0->v = 1;
*pc = '2';
pa1->v = 3;

std::printf("b.m_a0.v:%d\nb.c:%c\nb.m_a1.v:%d\n",
b.m_a0.v, b.c, b.m_a1.v);

return 0;
}
________________________________________________

This should be fine, A and B are POD's and work well with offsetof.

me

unread,
Sep 2, 2016, 3:27:26 PM9/2/16
to
Footnote 5) explicitly says that _any_ requirement
of the standard can be ignored as long as the observable behaviour
is correct. Yes, it's only a footnote, but clearly conveys the intent
of 1.9.1.

1.9.8 defines "observable behavior" in the obvious manner, which does
_not_ include (explicitly) anything to do with memory layout.

Finally (admittedly this is a less-than-language-lawyerly argument),
I think that all the guff about observable behaviour, as-if rule,
abstract machines, is about ensuring that the program produces
well-defined output and does what we think programs should do. We
want the correct prompts to show up for the user, we want the correct
bits to show up in files, etc., etc. To insist that the standard
would even _bother_ to care about struct layout except as it affects
observable behaviour seems utterly useless. (And this is supported
by footnote 5).

> >>> Given these two programs:
> >>> <program 1>
> >>> #include <cstdio>
> >>> struct S { int a; int b; };
> >>> struct S s = { 1, 2 };
> >>> int main(void){ printf("%d\n", s.a); return 0; }
> >>> </program 1>
> >>> and
> >>> <program 2>
> >>> #include <cstdio>
> >>> struct S { int b; int a; };
> >>> struct S s = { 2, 1 };
> >>> int main(void) { printf("%d\n", s.a); return 0; }
> >>> <program 2>
> >>>
> >>> If a compiler produced exactly, bit-for-bit, the same executable for
> >>> these two programs, would you complain to the vendor that they were
> >>> disobeying 9.2.13? What would you say to convince them that the as-if
> >>> rule _didn't_ apply?
> >>>
> >>
> >> Yes, because they are. What would YOU say to convince someone it is OK?
> >
> > My first recourse of course would be to reference 1.9.1. But maybe a
> > simpler approach would just be "Prove it". I.e., prove that in program 1
> > the memory address of s.a is higher than s.b, OR prove that in program 2
> > the memory address of s.a is lower than s.b.
> >
>
> And once again you are reading the standard wrong.

Okay, please explain how your correct reading is a counterargument to
my "prove it" argument. I.e., what statement in the standard _precludes_
both those programs producing identical executables. _Prove_ that the
addresses of the struct members are _not_ as the standard mandates.

> >>
> >> If your interpretation were correct, there would be no need for 9.2.13.
> >> But it's there - so there must be a reason. Maybe it's because you
> >> don't understand the as-if rule.
> >
> > Of course it's still needed. It describes certain observable behaviour,
> > like taking addresses and offsets of struct members. But in the absence
> > of taking those addresses, I really can't understand how "behaviour"
> > that is _completely_unobservable_ via standards-mandated means, could
> > possibly be construed as "observable behaviour".
> >
>
> Why is it still needed? It describes no behavior. It describes memory
> layout - which you just said is overridden by 1.9.1.

I phrased that poorly. _If_ it affects observable behaviour, i.e., _if_
addresses are taken or member offsets are used, _then_ the implementation
must take 9.2.13 into account to ensure that the observable behaviour
is correct. But 1.9.1 (plus footnote 5) says that if there is _no_ affect
on observable behaviour (as in my programs above), the implementation
can do any darn thing it pleases with struct layout.

Jerry Stuckle

unread,
Sep 2, 2016, 4:32:17 PM9/2/16
to
That is correct. Because 1.9.8 does not apply to structs (neither does
1.9.1).

>> And 1.9.1 refers to the remainder of section 1.9, not the entire
>> standard. Plus, 1.9 refers to program execution - not memory layout.
>> Layout is not behavior.
>
> 1.9.1 refers to the observable behaviour, which is defined "below" in
> 1.9.8. Section 1.9.8 refers to the entire rest of the standard.
>
> And memory layout is behaviour.
>

No, there is a difference. But you don't understand that.

>>
>> 1.9.1 is for things like the following:
>>
>> a = 2;
>> b = 3;
>> c = 2;
>>
>> Can be reordered to
>>
>> a = c = 2;
>> b = 3;
>>
>> Of course it's more than that. But to stay in line with what you can
>> understand, I'm keeping it simple.
>
> It covers /vastly/ more than that. It is the basis for the concept of
> an "optimising compiler".
>

As I said - it's a SIMPLIFIED EXAMPLE - meant for a SIMPLE MIND.
How about - ONE PASS. But then you need to see what each of those
unique passes does. Here's a hint: 206 of them are for code
optimization - not memory layout.

That's why in C anything must be declared before it can be used.

>
>>
>>> And if the compiler knows the definition of the function, then it will
>>> know which re-arrangements and optimisations are safe. With
>>> whole-program or link-time optimisation, the compiler may even know the
>>> definitions of every function in the program.
>>>
>>
>> Not before the structure has been defined.
>
> The compiler collects all the information about the program, data,
> structures, functions, etc., before it starts organising the data or
> generating the code. That's the point of whole-program optimisation.
>

Once again you are mistaken.

>>
>>>>
>>>> Just admit you are wrong and move on. Or explain why 9.2.13 exists,
>>>> when according to you, it is meaningless.
>>>>
>>>
>>> No, only you have claimed it is meaningless. I am quite happy with its
>>> meaning.
>>>
>>
>> No, you said the compiler is free to reorder the memory. That is in
>> direct conflict with 9.2.13. So it is you who declare it meaningless.
>
> Yes, the compiler is free to re-order anything it likes - code,
> functions, memory, structs, whatever - as long as the observable
> behaviour is unchanged.
>

Not according to 9.2.13. But you don't understand plain English.

>>
>> You are just digging yourself a deeper and deeper hole,
>>
>
> You simply don't understand much about how compilers work. That's okay,
> you don't have to know how they work in order to use them. But you do
> look silly by continuing to flaunt your ignorance.
>
> But keep going, if you like - it is somewhat entertaining. The idea
> that a modern C compiler is one-pass and generates the code for one line
> of source before reading the next line gave me a bit of a chuckle.
>

I understand completely how compilers work. I've worked on more of them
than you have. And yes, they are one pass through the source code. The
other passes are for optimization - which does NOT include reordering
structs.

But you don't understand standards.

But then trolls like you never were very smart. And you just continue
to dig yourself into deeper and deeper holes.

Jerry Stuckle

unread,
Sep 2, 2016, 4:38:14 PM9/2/16
to
On 9/2/2016 3:26 PM, me wrote:
--- nothing worth responding to.

You obviously are even more stoopid than some of the other trolls here.
I'm not even going to bother with you any more.

me

unread,
Sep 2, 2016, 4:51:57 PM9/2/16
to
On Friday, September 2, 2016 at 1:38:14 PM UTC-7, Jerry Stuckle wrote:
> On 9/2/2016 3:26 PM, me wrote:
> --- nothing worth responding to.
>
> You obviously are even more stoopid than some of the other trolls here.
> I'm not even going to bother with you any more.

Classic! I'm sure that will convince readers who can go back and look at
the history ...


Paavo Helde

unread,
Sep 2, 2016, 4:56:29 PM9/2/16
to
On 2.09.2016 22:26, me wrote:
> But 1.9.1 (plus footnote 5) says that if there is _no_ affect
> on observable behaviour (as in my programs above), the implementation
> can do any darn thing it pleases with struct layout.

I have got an impression that the most common thing which might happen
with a struct is that the compiler decides to place it into registers
altogether and there is no layout to speak of (what is the padding
between EAX and EBX?).

In regard of unions this becomes quite interesting. I imagine the
compiler might easily place the different union members in different
registers (except for the common initial sequence, if any). Using
different registers might make a lot of sense if one member is holding
integers and the other floating-point numbers, for example. I guess the
only thing which might hold the compiler developers back here is that
the union has a long tradition of being illegally abused for type-punning.

Cheers
Paavo




me

unread,
Sep 2, 2016, 5:16:37 PM9/2/16
to
Oh, and I humbly thank you for the honour of adding me to the list of
contributors you've called "stoopid".

I had a speech prepared ... now where are my notes ...?

Jerry Stuckle

unread,
Sep 2, 2016, 7:58:14 PM9/2/16
to
They sure can. And they will see what you really are.

Richard Damon

unread,
Sep 2, 2016, 9:48:56 PM9/2/16
to
Since the pragma doesn't begin with STDC it is implementation defined,
so does nothing as far as what the standard says must happen. Once you
are willing to depend on implementation defined behavior,you don't need
the pragma, as the implementation can document their padding rules and
define that padding won't be added in this case (the standard doesn't
require this to be documented, but it can be).

David Brown

unread,
Sep 3, 2016, 11:58:29 AM9/3/16
to
On 02/09/16 22:56, Paavo Helde wrote:
> On 2.09.2016 22:26, me wrote:
>> But 1.9.1 (plus footnote 5) says that if there is _no_ affect
>> on observable behaviour (as in my programs above), the implementation
>> can do any darn thing it pleases with struct layout.
>
> I have got an impression that the most common thing which might happen
> with a struct is that the compiler decides to place it into registers
> altogether and there is no layout to speak of (what is the padding
> between EAX and EBX?).
>

Certainly when you have small structs declared locally, you can expect
that some or all of the parts will be placed in registers. Other bits
might go onto the stack, or be removed entirely if they are not actually
needed.

> In regard of unions this becomes quite interesting. I imagine the
> compiler might easily place the different union members in different
> registers (except for the common initial sequence, if any). Using
> different registers might make a lot of sense if one member is holding
> integers and the other floating-point numbers, for example.

Yes, that sounds reasonable.

> I guess the
> only thing which might hold the compiler developers back here is that
> the union has a long tradition of being illegally abused for type-punning.
>

Note that this is only "illegal abuse" for C++ compilers that don't
allow it as an implementation-dependent feature. C compilers (from C99
onwards) have it as part of the standards, and C++ compilers such as gcc
allow it as implementation-dependent behaviour. Since all, or at least
almost all, C++ compilers are also C compilers, it would surprise me if
such type-punning unions work did not work correctly - at least in
simple cases. (Relying on this behaviour, unless it is documented by
your compiler, is of course a bad idea.)


David Brown

unread,
Sep 3, 2016, 12:08:22 PM9/3/16
to
On 02/09/16 22:32, Jerry Stuckle wrote:

<snip>

Jerry, you are wrong. You are talking absolute nonsense. You are
talking such complete and utter rubbish, that I suspect you actually
/do/ know a little about how compilers work - it would be hard to get so
many things wrong in so many ways by sheer idiocy and ignorance, so at
least part of what you write must be intentionally wrong.

I can only suppose you think it is fun to post this sort of stuff to
wind people up. Certainly that seems to be the only motivation for the
extraordinary levels of hatred and bile you pour out at people on
Usenet, and the totally unjustified insults you come out with. What a
sad, lonely little life you must lead when you gain pleasure from trying
to push other people down.

Jerry Stuckle

unread,
Sep 3, 2016, 6:25:44 PM9/3/16
to
Sorry, David. Once again you are throwing out the standards, based on
your incorrect assumptions. But such is the life of language lawyers
who think they know what is going on - but have absolutely no clue.

And those aren't insults. They are only the truth. Stoopid is as
stoopid does. And you have proven yourself time and time again to be
one of the worst. Starting when you claimed you couldn't determine
whether a machine was big endian or little endian at compiler time, and
I showed you wrong there, also.

The bottom line is - you don't know 10% of what you think you know. And
you never will until you humble up and figure out a lot of people know
more than you do - most of the world, in fact.

But then it seems many of the people in this newsgroup are in the same boat.

And FYI - the first compiler I wrote was a FORTRAN compiler in the early
70's in IBM 360 assembler. It was a side project since I had access to
a mainframe at the time.

One other thing - I lead a very happy life. One thing I have learned
over the years. I don't have to put up with stoopid idiots or trolls.
Life is too short to worry about what they think of me. When you start
paying me what my clients do or otherwise make a positive difference in
my life, I will start to care. Until then, you're not worth my worrying
about.

Mr Flibble

unread,
Sep 3, 2016, 6:51:48 PM9/3/16
to
On 03/09/2016 23:25, Jerry Stuckle wrote:
>
> And those aren't insults. They are only the truth. Stoopid is as
> stoopid does. And you have proven yourself time and time again to be
> one of the worst. Starting when you claimed you couldn't determine
> whether a machine was big endian or little endian at compiler time, and
> I showed you wrong there, also.

It is not possible with a standard conforming C++ compiler to determine
endianness at compile time.

Boost does offer a header file with platform specific information on
endianness however.

/Flibble

Jerry Stuckle

unread,
Sep 3, 2016, 9:48:42 PM9/3/16
to
Wrong again - as I showed here several months ago. However, I know it
is well beyond your limited level of comprehension.

Jerry Stuckle

unread,
Sep 3, 2016, 9:49:40 PM9/3/16
to
On 9/3/2016 6:51 PM, Mr Flibble wrote:
BTW - I though you were going to killfile me. I knew you wouldn't,
though. You have shown yourself to be much too obsessed with me. You
really need to get help with that obsession.

Mr Flibble

unread,
Sep 3, 2016, 10:49:02 PM9/3/16
to
On 04/09/2016 02:48, Jerry Stuckle wrote:
> On 9/3/2016 6:51 PM, Mr Flibble wrote:
>> On 03/09/2016 23:25, Jerry Stuckle wrote:
>>>
>>> And those aren't insults. They are only the truth. Stoopid is as
>>> stoopid does. And you have proven yourself time and time again to be
>>> one of the worst. Starting when you claimed you couldn't determine
>>> whether a machine was big endian or little endian at compiler time, and
>>> I showed you wrong there, also.
>>
>> It is not possible with a standard conforming C++ compiler to determine
>> endianness at compile time.
>>
>> Boost does offer a header file with platform specific information on
>> endianness however.
>>
>> /Flibble
>
> Wrong again - as I showed here several months ago. However, I know it
> is well beyond your limited level of comprehension.

Nope, it is not possible to determine endianness with a standard
conformant C++ compiler at compile time.

/Flibble


Mr Flibble

unread,
Sep 3, 2016, 10:49:43 PM9/3/16
to
On 04/09/2016 02:49, Jerry Stuckle wrote:
> On 9/3/2016 6:51 PM, Mr Flibble wrote:
>> On 03/09/2016 23:25, Jerry Stuckle wrote:
>>>
>>> And those aren't insults. They are only the truth. Stoopid is as
>>> stoopid does. And you have proven yourself time and time again to be
>>> one of the worst. Starting when you claimed you couldn't determine
>>> whether a machine was big endian or little endian at compiler time, and
>>> I showed you wrong there, also.
>>
>> It is not possible with a standard conforming C++ compiler to determine
>> endianness at compile time.
>>
>> Boost does offer a header file with platform specific information on
>> endianness however.
>>
>> /Flibble
>
> BTW - I though you were going to killfile me. I knew you wouldn't,
> though. You have shown yourself to be much too obsessed with me. You
> really need to get help with that obsession.

I will add you to my killfile at my pleasure.

/Flibble


Jerry Stuckle

unread,
Sep 3, 2016, 11:05:51 PM9/3/16
to
Sorry. Look back in this newsgroup. I proved it was possible. Look
back for yourself and see. I'm not going to bother to repeat it for a
troll.

That's the difference between a coder and a consultant. A coder says
"It can't be done". A consultant says "Here's how you do it".

But then you're barely a coder, so no surprise here.

Jerry Stuckle

unread,
Sep 3, 2016, 11:06:41 PM9/3/16
to
Fine with me. Then I won't have to put up with your bullshit. But I
know you won't. People like you are too obsessed. You need serious help.

Mr Flibble

unread,
Sep 4, 2016, 12:02:34 AM9/4/16
to

woodb...@gmail.com

unread,
Sep 4, 2016, 12:16:15 AM9/4/16
to
On Saturday, September 3, 2016 at 10:06:41 PM UTC-5, Jerry Stuckle wrote:

Jerry, please don't swear here.

Brian
Ebenezer Enterprises - In G-d we trust.
http://webEbenezer.net

Öö Tiib

unread,
Sep 4, 2016, 5:36:13 AM9/4/16
to
On Sunday, 4 September 2016 06:05:51 UTC+3, Jerry Stuckle wrote:
> On 9/3/2016 10:48 PM, Mr Flibble wrote:
> > On 04/09/2016 02:48, Jerry Stuckle wrote:
> >> On 9/3/2016 6:51 PM, Mr Flibble wrote:
> >>> On 03/09/2016 23:25, Jerry Stuckle wrote:
> >>>>
> >>>> And those aren't insults. They are only the truth. Stoopid is as
> >>>> stoopid does. And you have proven yourself time and time again to be
> >>>> one of the worst. Starting when you claimed you couldn't determine
> >>>> whether a machine was big endian or little endian at compiler time, and
> >>>> I showed you wrong there, also.
> >>>
> >>> It is not possible with a standard conforming C++ compiler to determine
> >>> endianness at compile time.
> >>>
> >>> Boost does offer a header file with platform specific information on
> >>> endianness however.
> >>>
> >>> /Flibble
> >>
> >> Wrong again - as I showed here several months ago. However, I know it
> >> is well beyond your limited level of comprehension.
> >
> > Nope, it is not possible to determine endianness with a standard
> > conformant C++ compiler at compile time.
> >
> > /Flibble
> >
> >
>
> Sorry. Look back in this newsgroup. I proved it was possible. Look
> back for yourself and see. I'm not going to bother to repeat it for a
> troll.

Perhaps you forget yourself what it was. Your example assumed that we
compile on equipment for what we compile. In practice we typically compile
on computer or on build farm that is LE platform. The target for what we
compile may be BE. So your "proof" does not work in practice.

People told you that but you did not respond anything coherent. Now you
refer to it like it was something settled. Who is troll here?

>
> That's the difference between a coder and a consultant. A coder says
> "It can't be done". A consultant says "Here's how you do it".
>
> But then you're barely a coder, so no surprise here.

Whining and bitching much?

Ben Bacarisse

unread,
Sep 4, 2016, 5:57:15 AM9/4/16
to
Mr Flibble <flibbleREM...@i42.co.uk> writes:

> On 04/09/2016 04:05, Jerry Stuckle wrote:
<snip>
>>>>> On 03/09/2016 23:25, Jerry Stuckle wrote:
>>>>>>
>>>>>> ... Starting when you claimed you couldn't determine
>>>>>> whether a machine was big endian or little endian at compiler time, and
>>>>>> I showed you wrong there, also.

>> Sorry. Look back in this newsgroup. I proved it was possible. Look
>> back for yourself and see. I'm not going to bother to repeat it for a
>> troll.
<snip>
> Nope, it is not possible to determine endianness with a standard
> conformant C++ compiler at compile time.

Just to remind people, Jerry Stuckle's "solution" is to write a program
to determine the byte order, and to use its output in the build of the
program that needs to know. This is, of course, not what people mean by
determining something "at compile time". He likely know this because it
removes any meaning from the phrase --- anything that can be determined
at run time can be determined at "Jerry Stuckle compile time".

--
Ben.

Tim Rentsch

unread,
Sep 4, 2016, 9:31:53 AM9/4/16
to
David Brown <david...@hesbynett.no> writes:

> On 02/09/16 03:08, Tim Rentsch wrote:
>> David Brown <david...@hesbynett.no> writes:
>>
>>> On 01/09/16 18:03, Tim Rentsch wrote:
>>>> Bo Persson <b...@gmb.dk> writes:
>>>>
>>>>> On 2016-08-31 15:20, David Brown wrote:
>>>>>> On 31/08/16 14:59, Melzzzzz wrote:
>>>>>>> Code in question is like this:
>>>>>>>
>>>>>>> struct Problem{
>>>>>>> uint32_t a;
>>>>>>> uint32_t b;
>>>>>>> uint64_t c;
>>>>>>> uint32_t d;
>>>>>>> bool check_it() {
>>>>>>> for (uint32_t* i = &a;i != &d; ++i)
>>>>>>> if (*i>0) return true;
>>>>>>> return false;
>>>>>>> }
>>>>>>>
>>>>>>> };
>>>>>>>
>>>>>>> I am not sure if this will work, so if someone has clear explanation
>>>>>>> why it will work (or not) , I would be grateful.
>>>>>>
>>>>>> I don't think you are guaranteed that a, b, c, and d follow each other
>>>>>> in the structure layout (though it is very likely to be the case). With
>>>>>> a pointer to a single item &a, incrementing the pointer is undefined
>>>>>> behaviour - as is accessing *i. And accessing the uint64_t member using
>>>>>> an uint32_t* pointer contradicts aliasing restrictions.
>>>>>>
>>>>>> All in all, the compiler is free to assume that this code is full of
>>>>>> undefined behaviour, therefore you don't really care what it does -
>>>>>> therefore it can all be optimised to "return true", "return false", or
>>>>>> even "launch nasal daemons". (This last option is legal for the
>>>>>> compiler, but thankfully unlikely in practice.)
>>>>>>
>>>>>> You can make it legal with:
>>>>>>
>>>>>> struct Problem {
>>>>>> union {
>>>>>> struct {
>>>>>> uint32_t a;
>>>>>> uint32_t b;
>>>>>> uint64_t c;
>>>>>> uint32_t d;
>>>>>> }
>>>>>> uint32_t as_array[5];
>>>>>> }
>>>>>> bool check_it() {
>>>>>> for (uint32_t* i = &as_array[0]; i != &as_array[4]; ++i)
>>>>>> if (*i > 0) return true;
>>>>>> return false;
>>>>>> }
>>>>>> }
>>>>>>
>>>>>> (Any issues regarding anonymous unions/structs are left as an exercise
>>>>>> for the reader :-)
>>>>>
>>>>> This might work in C, but a problem is that the C++ standard says:
>>>>>
>>>>> 9.3 Unions
>>>>> "In a union, a non-static data member is active if its name refers to
>>>>> an object whose lifetime has begun and has not ended (3.8). At most
>>>>> one of the non-static data members of an object of union type can be
>>>>> active at any time, that is, the value of at most one of the
>>>>> non-static data members can be stored in a union at any time. "
>>>>>
>>>>> So, if the struct with a, b, c, and d is active, as_array is not
>>>>> "stored" and cannot be read. You can't read an object that isn't
>>>>> there!
>>>>
>>>> So this is another way that C++ is not upwards compatible from
>>>> C?
>>>
>>> In theory, yes. But the platforms that support C++ are much more
>>> "normal" than those that support C, and there are far fewer C++
>>> compilers around. If all these C++ compilers support type punning
>>> through unions, as gcc and clang do, then there will be no
>>> incompatibility in practice.
>>
>> IMO it is unacceptably bad practice to write code that depends
>> on this sort of untestable guarantee.
>
> That is certainly true for some types of code. But a great deal of code
> does not need wide portability. [...]

I'm afraid you misunderstood my point, which has nothing to
do with running on multiple platforms.

Jerry Stuckle

unread,
Sep 4, 2016, 9:40:52 AM9/4/16
to
It satisfied the requirement. The determination was made at compile
time, and the result of the compile was dependent on whether the order
was little endian or big endian.

It's not my fault you didn't think of it. And people use external
programs during compile all the time. "make" is a good example, and it
can also set compile options.

Jerry Stuckle

unread,
Sep 4, 2016, 9:42:04 AM9/4/16
to
That was not part of the original requirement. You tried to change the
rules after the fact. It doesn't work.

>>
>> That's the difference between a coder and a consultant. A coder says
>> "It can't be done". A consultant says "Here's how you do it".
>>
>> But then you're barely a coder, so no surprise here.
>
> Whining and bitching much?
>

Nope, just pointing out the truth.

Tim Rentsch

unread,
Sep 4, 2016, 9:59:50 AM9/4/16
to
Chris Vine <chris@cvine--nospam--.freeserve.co.uk> writes:

> [...] Moving on from indeterminate values arising from padding to
> indeterminate values arising from uninitialized built-in types, C
> appears to do this much better than the proposal in what is now
> section 8.6/12 of N4606 for C++. C seems to provide that an
> uninitialised variable may hold a trap representation, but it may
> equally well have a valid (unknown) value in it,

The rule in C11 is just slightly more complicated, but that's
basically right.

> which is in fact
> what will happen on 99% or architectures and all those running
> C++. For the latter, these can be evaluated, say by copying.
> Section 8.6/12 of N4606 on the other hand provides for blanket
> undefined behaviour for any copying or other evaluation of an
> uninitialized object of built-in type which is not an unsigned
> narrow character (unsigned char, and char where char is unsigned).

I just read through these. Appalling.

For those who enjoy dark humor, it's amusing to note how these
passages increase the divergence between C++ and C: they make UB
in C++ for some cases that are defined in C, and they define
behavior in C++ for some cases that are UB in C. How perfect is
that?

> I don't like the way C++ sprays around undefined behaviour at the
> slightest provocation. Unions are another example.

I am sorry to say that I wholeheartedly agree. What C does is
bad enough, and based on a few areas I've looked at recently it
looks like C++ is worse.

Mr Flibble

unread,
Sep 4, 2016, 11:39:28 AM9/4/16
to
LOL. Obviously using code generation tools is not what people mean when
they say "determine at compile time". Determining something at compile
time is what can be achieved by the C++ compiler whilst it is compiling
an individual translation unit. So again you remain incorrect and we
remain correct:

It is not possible to determine endianness with a standard conformant
C++ compiler at compile time.

/Flibble

Jerry Stuckle

unread,
Sep 4, 2016, 12:46:33 PM9/4/16
to
The requirement was to determine at compile time whether the system is
big endian or little endian. My solution satisfied that requirement.
End of story.

No wonder you can't land a decent job.

Mr Flibble

unread,
Sep 4, 2016, 12:51:06 PM9/4/16
to
From the latest printing of the Oxford English Dictionary:

obtuse
Pronunciation: /əbˈtjuːs/
ADJECTIVE
1. Jerry Stuckle
'He wondered if this was another case of deliberate Jerry Stuckleness'

/Flibble


Luuk

unread,
Sep 4, 2016, 12:54:37 PM9/4/16
to
If the answer from Mr Stuckle is not correct, maybe the answer from
Stackoverflow is better?

http://stackoverflow.com/questions/4239993/determining-endianness-at-compile-time

bool isLittleEndian()
{
short int number = 0x1;
char *numPtr = (char*)&number;
return (numPtr[0] == 1);
}

Create an integer, and read its first byte (least significant byte). If
that byte is 1, then the system is little endian, otherwise it's big endian.

(less than 5 minutes of Google...)

Rick C. Hodgin

unread,
Sep 4, 2016, 12:59:04 PM9/4/16
to
Jerry Stuckle wrote:
> No wonder you can't land a decent job.

Is this the best way to help someone, Jerry? You profess to know
Jesus Christ as Lord and Savior ... is this what He said to the woman
caught in the act of adultery? "No wonder you can't be faithful to
your husband" ... Or did He say, "Neither do I condemn you. Go,
and sin no more" ?

Who are you serving with belittling speech? Is it Jesus Christ? Or is there
another spirit who seeks to belittle and demean?

Best regards,
Rick C. Hodgin

Mr Flibble

unread,
Sep 4, 2016, 12:59:12 PM9/4/16
to
No because isLittleEndian() cannot be called at COMPILE TIME. Try
paying attention.

/Flibble

Jerry Stuckle

unread,
Sep 4, 2016, 1:07:18 PM9/4/16
to
Your obsession with me is quite sick. But then that's just like the
troll you are.

I suggest you seek psychiatric help quickly.

Jerry Stuckle

unread,
Sep 4, 2016, 1:08:29 PM9/4/16
to
Rick, I've tried to help Flibbie multiple times. He is incapable of
learning.

And I don't need any of your self-righteous preaching. Take it to an
appropriate newsgroup - as so many have asked you to do.

Jerry Stuckle

unread,
Sep 4, 2016, 1:09:02 PM9/4/16
to
That's not done at compile time - which is what the requirement was.

Rick C. Hodgin

unread,
Sep 4, 2016, 1:22:01 PM9/4/16
to
Jerry Stuckle wrote:
> Rick, I've tried to help Flibbie multiple times. He is incapable of learning.

That is in no way true. One's approach is often the impediment in
how able another is to learn. You must meet all people wheee they
are. And you must teach, not belittle or demean.

> And I don't need any of your self-righteous preaching.

I am not advocating me, but I am asking you to reflect upon your own
public actions, holding them yourself before Jesus Christ for scrutiny.
He will guide you and temper your responses ... if you'll allow Him.

Mr Flibble

unread,
Sep 4, 2016, 1:37:51 PM9/4/16
to
On 04/09/2016 18:07, Jerry Stuckle wrote:
> Your obsession with me is quite sick. But then that's just like the
> troll you are.
>
> I suggest you seek psychiatric help quickly.

You think I am obsessed with you yet I am on the verge of killfiling you
now that I have the full measure of you.

/Flibble


David Brown

unread,
Sep 4, 2016, 2:19:24 PM9/4/16
to
So you are happy that some code is implementation-dependent, and if the
implementation documents a given behaviour it is okay to rely on it?

But if code is supposed to be portable (either across different current
toolchains, or to unknown future ones), then you can't rely on it. And
if the implementation seems to work for the given code, but does not
documentation a guarantee, then it may be a very risky thing to rely on
it - but it may be acceptable in certain circumstances.

What am I missing, or misunderstanding here?

David Brown

unread,
Sep 4, 2016, 2:25:25 PM9/4/16
to
This is done at run-time, just like Jerry's "solution". The difference
is that Jerry takes the output of a function like isLittleEndian(), and
uses it to affect the compilation of a different file (by using it to
generate a header, or something like that - I have forgotten the
details). Of course, Jerry's "solution" is no more of a compile-time
solution than this one is. In fact, it is far worse, because it fails
when doing cross-compilation.


Jerry Stuckle

unread,
Sep 4, 2016, 5:16:15 PM9/4/16
to
ROFLMAO! You are so obsessed you need to reply to every post I make -
even those not addressed to you.

Please - for your own sake, get help. The sooner the better.

Jerry Stuckle

unread,
Sep 4, 2016, 5:19:06 PM9/4/16
to
On 9/4/2016 1:21 PM, Rick C. Hodgin wrote:
> Jerry Stuckle wrote:
>> Rick, I've tried to help Flibbie multiple times. He is incapable of learning.
>
> That is in no way true. One's approach is often the impediment in
> how able another is to learn. You must meet all people wheee they
> are. And you must teach, not belittle or demean.
>

Rick, I've tried many times with Flibbie and others. After a time, it's
no longer worth my effort. I have better things to do in life.

>> And I don't need any of your self-righteous preaching.
>
> I am not advocating me, but I am asking you to reflect upon your own
> public actions, holding them yourself before Jesus Christ for scrutiny.
> He will guide you and temper your responses ... if you'll allow Him.
>
> Best regards,
> Rick C. Hodgin
>

You are preaching, and your preaching is not wanted. By me or other
people here, as you have already been told.

Real Christians know when religious discussions are appropriate and when
they are not. However, Satan is very insidious in his methods of
driving people away from Christ. Preaching where it is not welcome is
one of them.

I would suggest you consider that thought.

Jerry Stuckle

unread,
Sep 4, 2016, 5:20:59 PM9/4/16
to
No, my solution was done at compile time, just like your requirement.
And you never said anything about cross-compilation. Had you done so, I
would have supplied a different solution.

But you never do admit you are wrong. This is a perfect example. You
said it could not be done, and I showed you how to do it. So instead of
admitting you were wrong and I was right, you tried to change the
requirements.

It doesn't work.

Mr Flibble

unread,
Sep 4, 2016, 5:23:18 PM9/4/16
to
On 04/09/2016 22:16, Jerry Stuckle wrote:
> On 9/4/2016 1:37 PM, Mr Flibble wrote:
>> On 04/09/2016 18:07, Jerry Stuckle wrote:
>>> Your obsession with me is quite sick. But then that's just like the
>>> troll you are.
>>>
>>> I suggest you seek psychiatric help quickly.
>>
>> You think I am obsessed with you yet I am on the verge of killfiling you
>> now that I have the full measure of you.
>>
>> /Flibble
>>
>>
>
> ROFLMAO! You are so obsessed you need to reply to every post I make -
> even those not addressed to you.

I reply to any of your posts that are blatantly incorrect: the problem
is that that is the case for almost 100% of them.

>
> Please - for your own sake, get help. The sooner the better.

Classic example of psychological projection.

/Flibble


Mr Flibble

unread,
Sep 4, 2016, 5:25:01 PM9/4/16
to
So you believe in the existence a magical sky daddy too do you Stuckle?
That explains quite a lot.

/Flibble


Jerry Stuckle

unread,
Sep 4, 2016, 6:55:04 PM9/4/16
to
On 9/4/2016 5:23 PM, Mr Flibble wrote:
> On 04/09/2016 22:16, Jerry Stuckle wrote:
>> On 9/4/2016 1:37 PM, Mr Flibble wrote:
>>> On 04/09/2016 18:07, Jerry Stuckle wrote:
>>>> Your obsession with me is quite sick. But then that's just like the
>>>> troll you are.
>>>>
>>>> I suggest you seek psychiatric help quickly.
>>>
>>> You think I am obsessed with you yet I am on the verge of killfiling you
>>> now that I have the full measure of you.
>>>
>>> /Flibble
>>>
>>>
>>
>> ROFLMAO! You are so obsessed you need to reply to every post I make -
>> even those not addressed to you.
>
> I reply to any of your posts that are blatantly incorrect: the problem
> is that that is the case for almost 100% of them.
>

Sorry, the post was completely correct. You didn't even know the
question, so how could you say the answer was "blatantly incorrect"?

Oh, that's because of your obsession with me. You think anything I say
is incorrect.

>>
>> Please - for your own sake, get help. The sooner the better.
>
> Classic example of psychological projection.
>
> /Flibble
>
>

Yes, and you have a really bad case of it - in addition to your
obsession with me. You need serious help.

Jerry Stuckle

unread,
Sep 4, 2016, 6:56:07 PM9/4/16
to
Ah, once again your obsession shows its ugly face. You are just showing
how bad it is - having to reply to every post I make, whether it applies
to you or not.

Do yourself and everyone else a favor. Get help, and quick.

Mr Flibble

unread,
Sep 4, 2016, 7:27:42 PM9/4/16
to
Whether it applies to me or not? Try scrolling up you demented fuckwit.

>
> Do yourself and everyone else a favor. Get help, and quick.

Take your own advice.

/Flibble


It is loading more messages.
0 new messages