size of struct problem

Started by
8 comments, last by executor_2k2 21 years, 11 months ago
I have a struct defined as follows: struct pos_t { unsigned long framenum; unsigned short accel; float pos_x, pos_y, pos_z; }; I did a "sizeof(pos_t)" and got 20 bytes. Shouldnt it be 18? Shorts are 2, floats are 4, longs are 4, right? Please correct me if Im wrong. Im writing in C++ on msvc++ 6.0. Thanks.
Well, that was a waste of 2 minutes of my life. Now I have to code faster to get 'em back...
Advertisement
It depends on your structure alignment. If you''re using a 32 bit compiler, as you probably are, I think the default alignment is 8 bytes or 4 bytes. This is because 32 bit processors prefer handling data in 32 bit chunks (4 bytes), so the compiler automatically aligns the structs to multiples or 4 or 8 bytes. If you change the struct alignment to 1 or 2 bytes, you should get 18, but this will result in worse performance.
Structure members don''t have to be stored consecutively in memory. Different systems can only allocate data on certain memory boundaries like half-word, word, or dword. Or in other words, the size of data items of a particular type is machine dependent, and because storage alignment considerations are machine dependent, so is the representation of the structure, too. Take this, for example:
struct s
{
double d1;
bool b1;
};

Theoretically, it should take up only 9 bytes in VC++ 7, but it takes up 16 bytes due to restrictions stated above.

Sometimes you can cut down the size of a structure significanly by simply rearranging its members so try different combinations if your struct seems bloated. Rearraning doesn''t always work, nevertheless it''s worth a shot.
Any amount of padding can be placed anywhere in the struct, except at the beginning. sizeof isn''t lying.
char a[99999],*p=a;int main(int c,char**V){char*v=c>0?1[V]:(char*)V;if(c>=0)for(;*v&&93!=*v;){62==*v&&++p||60==*v&&--p||43==*v&&++*p||45==*v&&--*p||44==*v&&(*p=getchar())||46==*v&&putchar(*p)||91==*v&&(*p&&main(0,(char**)(--v+2))||(v=(char*)main(-1,(char**)++v)-1));++v;}else for(c=1;c;c+=(91==*v)-(93==*v),++v);return(int)v;}  /*** drpizza@battleaxe.net ***/
you can modify padding, look at your project settings (if using VC++). there are also pargama commands you can use to modify it on a per struct basis. see your compiler manual, and search the net for further info.

useful for structs that you may use to read from files with, but NOT for general stuff as it will very likly slow memory access.
Well, it''s better to just ensure the data members are evenly divisible by 32 bits. In this example, there''s no reason for accel to be a short because that only saves you 2 bytes (even with many instances of these, that''s insignificant) and it slows performance.

~CGameProgrammer( );

~CGameProgrammer( );Developer Image Exchange -- New Features: Upload screenshots of your games (size is unlimited) and upload the game itself (up to 10MB). Free. No registration needed.
Well, the struct is defined by the .3ds format, so i cant do too much about the short. The struct defined by the .3ds format is 18 bytes which is not evenly divisible by 8(default packing). If I just set packing to 1 with "#pragma pack 1" will i be able to create a struct that's the same size as the one defined in the .3ds specification? Also, how do I set packing back to 8 after I make my 3ds structs? Thanks.

[edited by - executor_2k2 on May 4, 2002 1:42:41 AM]
Well, that was a waste of 2 minutes of my life. Now I have to code faster to get 'em back...
OK, I have an idea. If you really want the
data in memory to be tightly packed
(meanin no padding), I have a neat trick.
You can define a block of 18 bytes (characters).
Then assign references to specific locations in that
block of memory. Here's an example:


    #include <iostream.h>class pos_t{public:pos_t();char data[18];unsigned long& framenum;unsigned short& accel;float& pos_x;float& pos_y;float& pos_z;};pos_t::pos_t():framenum(*((unsigned long*)data)),		//bytes 0 - 3accel(*((unsigned short*)(data + 4))),	        //bytes 4 - 5pos_x(*((float*)(data +  6))),			//bytes 6 - 9pos_y(*((float*)(data + 10))),			//bytes 10 - 13pos_z(*((float*)(data + 14)))			//bytes 14 - 17{	cout << "this = " << this << endl;	cout << (&framenum) << endl;	cout << (&accel) << endl;	cout << (&pos_x) << endl;	cout << (&pos_y) << endl;	cout << (&pos_z) << endl;}int main (){	pos_t p;	cout << "sizeof(pos_t) = " << sizeof(pos_t) << endl;	return 0;}    


If you run the program, you might notice that the size of the
class itself is 40 bytes. That's probably due (at least in part)
to the underlying implementation of references by using pointers.
However, the actual data you're interested in is tightly packed
and starts at pos_t::data.



Steven Borkman
Home Page: http://www.borkman.mygamesite.net
Video Game Page: http://www.dev.mygamesite.net

[edited by - borkman on May 4, 2002 2:42:20 AM]
I don't if this applies to your platform/compiler, but on my system:

1. Every variable/member is aligned on a boundary equal to its size. So a two-byte short is aligned on a two-byte boundary. A four-byte int is aligned on a four-byte boundary...

2. A struct takes the alignment of the member with the largest alignment. So if the struct is full of two-byte shorts, it will be aligned on a two-byte boundary. If the struct contains a two-byte short and a four-byte int, the struct will be aligned on a four-byte boundary. The rule is recursive and applies to structs nested inside of each other...

[edited by - poozer on May 4, 2002 4:09:32 AM]
quote:Original post by poozer
I don't if this applies to your platform/compiler, but on my system:

1. Every variable/member is aligned on a boundary equal to its size. So a two-byte short is aligned on a two-byte boundary. A four-byte int is aligned on a four-byte boundary...

What system is that?

Certainly not anything in common usage.

The only computer platform in common usage -- x86 -- permits unaligned access of all types, (except for the SIMD data types), and will, even with reasonable efforts by the compiler, still occasionally require unaligned data access. There's a particular issue with the 64 and 80-bit floating point types, as such variables, when created on the stack; the stack is normally (always?) only 4-byte aligned; either special fix-up code needs to be injected to align such floating point types properly, or they are just left unaligned.



[edited by - DrPizza on May 4, 2002 6:12:23 AM]
char a[99999],*p=a;int main(int c,char**V){char*v=c>0?1[V]:(char*)V;if(c>=0)for(;*v&&93!=*v;){62==*v&&++p||60==*v&&--p||43==*v&&++*p||45==*v&&--*p||44==*v&&(*p=getchar())||46==*v&&putchar(*p)||91==*v&&(*p&&main(0,(char**)(--v+2))||(v=(char*)main(-1,(char**)++v)-1));++v;}else for(c=1;c;c+=(91==*v)-(93==*v),++v);return(int)v;}  /*** drpizza@battleaxe.net ***/

This topic is closed to new replies.

Advertisement