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

Strange behaviour - struct and sizeof

3 views
Skip to first unread message

ropo

unread,
Sep 6, 2007, 6:22:59 AM9/6/07
to
I have a structure thus:


struct MyStruct
{
int _intMem;
double _doubleMem;
};

sizeof(int) + sizeof(double) == 4 + 8 == 12

BUT!

sizeof(MyStruct) == 16

Why?

Joe Butler

unread,
Sep 6, 2007, 6:50:54 AM9/6/07
to
The compiler aligns individual elements of the stuct on 8-byte boundaries
(because it makes it faster for the processor to access the individual
elements).

If you need the elements fitting snuggly together, you need to tell the
compiler that you want 1-byte structure alignment.


"ropo" <ARo...@yahoo.co.uk> wrote in message
news:1189074179....@r34g2000hsd.googlegroups.com...

Ulrich Eckhardt

unread,
Sep 6, 2007, 8:46:07 AM9/6/07
to
Joe Butler wrote:
> The compiler aligns individual elements of the stuct on 8-byte boundaries
> (because it makes it faster for the processor to access the individual
> elements).

Errm, that statement is misleading. The compiler aligns individual elements
to their respective alignment requirements. For double, that is 8 bytes,
for int that would be 4 bytes.

> If you need the elements fitting snuggly together, you need to tell the
> compiler that you want 1-byte structure alignment.

... and sacrifice performance.

> "ropo" <ARo...@yahoo.co.uk> wrote:
>> struct MyStruct
>> {
>> int _intMem;
>> double _doubleMem;
>> };
>>
>> sizeof(int) + sizeof(double) == 4 + 8 == 12
>>
>> BUT!
>>
>> sizeof(MyStruct) == 16

The thing is called 'padding', doing a websearch on that topic will turn up
lots of info.

Uli

Duane Hebert

unread,
Sep 6, 2007, 10:03:10 AM9/6/07
to

"Ulrich Eckhardt" <eckh...@satorlaser.com> wrote in message
news:fd95r4-...@satorlaser.homedns.org...
> Joe Butler wrote:

>> If you need the elements fitting snuggly together, you need to tell the
>> compiler that you want 1-byte structure alignment.
>
> ... and sacrifice performance.

Have you ever been able to benchmark
any significant decrease in performance
caused by pragma pack(1) ?

We do a bunch of cross platform stuff and
this is about the only way to deal with this
so I'm curious. We haven't seen any issues
yet.

Ulrich Eckhardt

unread,
Sep 6, 2007, 10:55:02 AM9/6/07
to

No I haven't. However, the question is also how you use it. If all you do is
this:

packed_struct p;
... // fill p
output.write( &p, sizeof p);

you will probably be fine because it is a rare case and the overhead of IO
dominates anyway.

The main difference is that an aligned access can be done in one step on
most architectures, while an unaligned access will (more or less) be
performed bytewise. Note that on x86 it might look like one step (single
instruction) but is in fact several steps too, only that they are emulated
by the hardware.

Uli


Duane Hebert

unread,
Sep 6, 2007, 11:30:25 AM9/6/07
to

"Ulrich Eckhardt" <eckh...@satorlaser.com> wrote in message
news:7vg5r4-...@satorlaser.homedns.org...

> Duane Hebert wrote:
>> "Ulrich Eckhardt" <eckh...@satorlaser.com> wrote in message
>> news:fd95r4-...@satorlaser.homedns.org...
>>> Joe Butler wrote:
>>
>>>> If you need the elements fitting snuggly together, you need to tell the
>>>> compiler that you want 1-byte structure alignment.
>>>
>>> ... and sacrifice performance.
>>
>> Have you ever been able to benchmark
>> any significant decrease in performance
>> caused by pragma pack(1) ?
>>
>> We do a bunch of cross platform stuff and
>> this is about the only way to deal with this
>> so I'm curious. We haven't seen any issues
>> yet.
>
> No I haven't. However, the question is also how you use it. If all you do
> is
> this:
>
> packed_struct p;
> ... // fill p
> output.write( &p, sizeof p);

That's pretty much what it's for in
our case. Mostly writing/reading
over sockets.


> you will probably be fine because it is a rare case and the overhead of IO
> dominates anyway.
>
> The main difference is that an aligned access can be done in one step on
> most architectures, while an unaligned access will (more or less) be
> performed bytewise. Note that on x86 it might look like one step (single
> instruction) but is in fact several steps too, only that they are emulated
> by the hardware.

I'm aware of this but I've never been able to
measure anything significant. Just checking.


Nathan Mates

unread,
Sep 6, 2007, 12:43:27 PM9/6/07
to
In article <1189074179....@r34g2000hsd.googlegroups.com>,

ropo <ARo...@yahoo.co.uk> wrote:
>struct MyStruct
>{
> int _intMem;
> double _doubleMem;
>};

The best way to ensure your structs pack in as snugly as possible,
assuming that you can reorder the contents: order the member variables
starting with the largest. In other words, with the builtin C/C++
types, order them as follows:

1st) 8-byte entries: doubles
2nd) 4/8-byte entries: pointers (you are ready for 64 bits, right?)
3rd) 4 byte entries: floats, ints, "DWORD" and other MS-isms
4th) 2 byte entries: shorts, "WORD" and other MS-isms
5th) 1 byte entries: chars

If you have arrays, do the multiplication to figure out where they
fit in the the above list. If you have structs/classes, then do the
math once again to figure out how to pack them. As long as you follow
the largest-to-smallest, your overhead is minimized w/o having to
tweak packing rules.

I've said this before: I'd really like a pragma that tells the
compiler "I don't care about the order of items in this struct --
reorder them if you think you can pack them better." Or at least a
pragma that turns on a warning when more than some % of a
struct/class's size is due to packing/alignment issues. Compilers are
treated as magic black boxes, but with a little bit of dialog, they
can be far more useful.

Nathan Mates
--
<*> Nathan Mates - personal webpage http://www.visi.com/~nathan/
# Programmer at Pandemic Studios -- http://www.pandemicstudios.com/
# NOT speaking for Pandemic Studios. "Care not what the neighbors
# think. What are the facts, and to how many decimal places?" -R.A. Heinlein

Alexander Nickolov

unread,
Sep 6, 2007, 1:01:03 PM9/6/07
to
Even this is not precise, as the alignment value is the lesser of
the field type's alignment requirement and the struct's packing.
The default struct packing is 8 bytes, but it can be changed in
the project settings and can always be overridden via
#pragma pack().

--
=====================================
Alexander Nickolov
Microsoft MVP [VC], MCSD
email: agnic...@mvps.org
MVP VC FAQ: http://vcfaq.mvps.org
=====================================

"Ulrich Eckhardt" <eckh...@satorlaser.com> wrote in message
news:fd95r4-...@satorlaser.homedns.org...

Message has been deleted

Jeff☠Relf

unread,
Sep 6, 2007, 7:11:10 PM9/6/07
to
There's an implicit “ __int32 ” in the middle of the struct:

#pragma warning( disable: \
4007 4101 4189 4244 4305 4430 4508 4706 4709 4996 )
WinMain( int, int, int, int ) { int rv ;

struct tRec { __int32 X ; __int64 Y ; }; tRec Rec ;

typedef char * pChar ;
rv = pChar( & Rec.X ) - pChar( & Rec );
// rv is now “ 0 ”.

rv = pChar( & Rec.Y ) - pChar( & Rec );
} // rv is now “ 8 ”.

Tim Roberts

unread,
Sep 7, 2007, 12:33:49 AM9/7/07
to
"Duane Hebert" <sp...@flarn.com> wrote:

>"Ulrich Eckhardt" <eckh...@satorlaser.com> wrote:
>> Joe Butler wrote:
>
>>> If you need the elements fitting snuggly together, you need to tell the
>>> compiler that you want 1-byte structure alignment.
>>
>> ... and sacrifice performance.
>
>Have you ever been able to benchmark
>any significant decrease in performance
>caused by pragma pack(1) ?

I can give you an example.

Take this structure as an example:

#pragma pack(1)
struct {
unsigned short x1;
unsigned int x2;
unsigned short x3;
} testing;

Back in the days when Windows NT ran on RISC processors, this kind of thing
was a real problem. Trying to read testing.x2 on an Alpha, for example,
actually caused a trap to kernel mode, where an exception handler had to
decode the instruction and use shifting-and-masking to fetch the
appropriate bits.

It was FABULOUSLY expensive, and was a real wake-up call to folks who had
been weaned on x86 processors all of their lives.
--
Tim Roberts, ti...@probo.com
Providenza & Boekelheide, Inc.

Tim Roberts

unread,
Sep 7, 2007, 12:40:25 AM9/7/07
to
Jeff?Relf <Jeff...@Yahoo.COM> wrote:

Absolutely true, and quite well-documented. With the default settings, the
compiler aligns each structure member to its "natural" alignment. Shorts
are aligned to a 2-byte boundary, dwords to a 4-byte boundary, 64-bit
values to an 8-byte boundary. In order to get Y to an 8-byte boundary, it
inserts 4 bytes of padding.

"#pragma pack" can be used to override this. The value you provide is the
maximum alignment value the compiler can use. So, if you modify your code
to this:

#pragma pack(1)
struct rec { __int32 X ; __int64 Y ; }; tRec Rec;
#pragma pack()

you will see the results you expect, at the possible cost of decreased
performance because of unaligned fetches.

Ordinarily, you do not need to worry about this unless you are writing
structures to a file or socket for transport to another computer, or are
working with a piece of hardware.

Carl Daniel [VC++ MVP]

unread,
Sep 7, 2007, 1:13:43 AM9/7/07
to

IIUC, the same happens on Itanium processors today (and SPARC, and PowerPC).

-cd


Duane Hebert

unread,
Sep 7, 2007, 6:18:25 AM9/7/07
to

"Tim Roberts" <ti...@probo.com> wrote in message
news:j0l1e35ve63qt1l2u...@4ax.com...

Yikes. Thanks.


Alexander Nickolov

unread,
Sep 7, 2007, 12:55:09 PM9/7/07
to
Well, of course. That's what member alignment means after all.
And your point is?

--
=====================================
Alexander Nickolov
Microsoft MVP [VC], MCSD
email: agnic...@mvps.org
MVP VC FAQ: http://vcfaq.mvps.org
=====================================

"Jeff?Relf" <Jeff...@Yahoo.COM> wrote in message
news:Jeff_Relf_2007...@Cotse.NET...

Jeff☠Relf

unread,
Sep 7, 2007, 2:26:00 PM9/7/07
to
Looking at the virtual sea of binary records
my 15 year old code saves to the disk,
I noticed that absolutely all of the fields are 4 bytes long.

I could convert that to XML, but I don't see the advantage.

When an interface is requested,
my code generates a much simpler, special-case text file
along with code to read it back in, once modified.

In fact, that's exactly what I'm working on now ( for money ).

Jeff☠Relf

unread,
Sep 7, 2007, 3:24:23 PM9/7/07
to
Some of the fields I save to the disk are structs of course;
but, as the code below shows,
by VC++ 8.0's default, none are aligned on 8 byte boundries.

#pragma warning( disable: \
4007 4101 4189 4244 4305 4430 4508 4706 4709 4996 )

WinMain( int, int, int, int ) { float rv ;

struct tOdd { __int32 X, Y, Z ; }; tOdd Odd ;
rv = float( sizeof Odd ) / sizeof( __int32 );
// “ rv ” is now “ 3.0 ”.

struct tRec { tOdd Odd, Odd2 ; }; tRec Rec ;
rv = float( sizeof Rec ) / sizeof( __int32 );
// “ rv ” is now “ 6.0 ”.

Alexander Nickolov

unread,
Sep 7, 2007, 8:38:56 PM9/7/07
to
Replying to your other post, since you have malformed
References: header and it can't be replied to directly...

If you read my earlier post you'll find the answer yourself.
Of course the struct packing does not dictate the member
offsets. It only serves to limit the alignment necessitated by
the member's type.

--
=====================================
Alexander Nickolov
Microsoft MVP [VC], MCSD
email: agnic...@mvps.org
MVP VC FAQ: http://vcfaq.mvps.org
=====================================

"Jeff?Relf" <Jeff...@Yahoo.COM> wrote in message
news:Jeff_Relf_2007...@Cotse.NET...

> Some of the fields I save to the disk are structs of course;
> but, as the code below shows,
> by VC++ 8.0's default, none are aligned on 8 byte boundries.
>

> #pragma warning( disable: \
> 4007 4101 4189 4244 4305 4430 4508 4706 4709 4996 )

> WinMain( int, int, int, int ) { float rv ;
>
> struct tOdd { __int32 X, Y, Z ; }; tOdd Odd ;

> rv = float( sizeof Odd ) / sizeof( __int32 );
> // " rv " is now " 3.0 ".


>
> struct tRec { tOdd Odd, Odd2 ; }; tRec Rec ;

> rv = float( sizeof Rec ) / sizeof( __int32 );
> // " rv " is now " 6.0 ".
>


Jeff☠Relf

unread,
Sep 7, 2007, 9:08:34 PM9/7/07
to
Re: Your ( Mr. Nickolov's ) inablity to reply to:
“ news:Jeff_Relf_2007...@Cotse.NET ”,

There's nothing wrong with the headers.
If there were, and you could show me the problem,
I'd gladly eat my shorts, live on camera.

If I'm not mistaken, your “ Expertcity.COM ” is having problems.
Didn't your post take 10 minutes to arrive ?

My “ News.Individual.NET:8119
has a gigabit connection to the internet;
when I post, it shows up immediately.

Scott Seligman

unread,
Sep 8, 2007, 2:38:00 AM9/8/07
to
<Jeff...@Yahoo.COM> wrote:
>
>Re: Your ( Mr. Nickolov's ) inablity to reply to:
>news:Jeff_Relf_2007...@Cotse.NET
>
>There's nothing wrong with the headers.

Yes there is. From:
http://groups.google.com/group/microsoft.public.vc.language/msg/14300ffe02dc676f?dmode=source
Your post contained the following:
] References: <46dfda42$0$13929$fa0f...@news.zen.co.uk>
] <fd95r4-...@satorlaser.homedns.org>
] <e0qk2dK8...@TK2MSFTNGP02.phx.gbl>
] <Jeff_Relf_2007...@Cotse.NET>
] <ucpSO$W8HHA...@TK2MSFTNGP06.phx.gbl>
] <_ Jeff_Relf_2007_...@Cotse.NET>

That last message ID is either wrong, or when you posted that message,
you posted it with an invalid message id. Either way, it's broken.

>If there were, and you could show me the problem,
>I'd gladly eat my shorts, live on camera.

I'd just be happy if you'd follow nettiquite like the rest of the
group.

--
--------- Scott Seligman <scott at <firstname> and michelle dot net> ---------
Never do today what you can put off till tomorrow. Delay may give
clearer light as to what is best to be done.
-- Aaron Burr

Jeff☠Relf

unread,
Sep 8, 2007, 3:02:47 AM9/8/07
to
Oops, now I have to eat my shorts live on camera.
But I never said when... How about January 1st, 2060 ?

Re: This malformed MessageID ( in the “ References ” field ):
“ _ Jeff_Relf_2007_...@Cotse.NET ”.

It's a rarely occuring bug, related to some semi-recent changes,
“ nettiquite ” has nothing to do with it.
I'll fix it in a minute or two and upload a new “ Games.ZIP ”.

Normally, the thread is there, in the “ References ” field;
so I don't feel sorry for anyone who can't ( or won't ) read it.

Jeff☠Relf

unread,
Sep 8, 2007, 4:54:14 AM9/8/07
to
Re: “ news:Jeff_Relf_2007...@Cotse.NET ”
with this malformed MessageID in the “ References ” field:
“ _ Jeff_Relf_2007_...@Cotse.NET ”.

It only happened when I replied to one of my own posts.

Now each MID in the list of recent ancestors can have the form:
“ Optional_Nym Mes...@ID.COM ”,
where “ Optional_Nym ” may or may not be there.

For example, this is a screenshot of
what this post looked like just before I posted it:
www.Cotse.NET/users/jeffrelf/AboutToPost.PNG

The newsreader, X.EXE, is in:
www.Cotse.NET/users/jeffrelf/Games.ZIP ”.

0 new messages