Sign in to follow this  

Sequential Memory - is this safe?

This topic is 4864 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Recommended Posts

I've always wondered this. Lets say we have a structure: struct Thing { float property1; float property2; int property3; int property4; } And then we allocate some of these structures in memory. For one structure, are all the properties in one contiguous memory space? Like property4 is right after property3, which is right after property2, etc. So it would be safe to do something like this. unsigned char *buffer = &thingInstance.property1; float retrievedProperty2 = buffer+sizeof(float); Would it be safe to bet that it is always the case- that the memory is contiguous for the structure?

Share this post


Link to post
Share on other sites
No, because of packing. You might be able to disable the packing with compiler #pragmas or similar, but some cpu's can't cope with 32 bit accesses not on 32 bit boundaries.

You can always use a macro
#define OFFSET_OF( var_, field_ ) ( &var_.field_ - &var_ )

to get the offset in sizeof units.

e.g. OFFSET_OF(thingInstance, property2)

expands to &thingInstance.property2 - &thingInstance, which is what you want.

Share this post


Link to post
Share on other sites
Not always, the compiler might do some padding to align the data for highest performance, ie:

struct
{
char a;
int b;
};

With default packing settings the compiler would probably insert 3 bytes of unused data between a and b to make sure b is on a 4-byte boundary. If it isnt, it will be slower to access. If you are using visual c++ you can change the settings with #pragma pack or in the project settings dialog, and there are similiar switches in other compilers as well.

Though in your case all your properties will be in contiguous memory since each one is 4 bytes in size and no padding is necessary.

Share this post


Link to post
Share on other sites
Interesting. Thanks for the information. I probably won't end up using it, but just wanted to know if the technique is even available.

Actually, I might implement a function in my vector class that returns a float pointer. Currently the vector has members x, y, and z... They are not in a structure, but they are declared contiguously, and they are each 4 bytes. So I think it would still be safe to 'return &x'?

Share this post


Link to post
Share on other sites
Actually this sort of thing is done in file loaders all the time.


struct fileheader
{
long headerSize;
long dataSize
char someHeaderCrap[24];
long someMoreHeaderCrap;
short justALittleBitMoreCrap;
short padding;

byte[1] fileDataGoesHere;
};

// then, somewhere in your file loading code...

fileheader* pFile = (fileheader*) new byte[totalFileSize];
fread(pfile,totalFileSize,1,f);




As has already been said, you need to be aware of packing issues between different sized variables, and how to override this when it's necessary using #pragmas.

Also, if you just want to be able to access your data in different ways, then unions might be a useful thing. let's suppose you had a vector structure, and you wanted array access to the elements as well as explicit access (x, y z, etc...) you could do this using unions.


union vector3
{
struct
{
float x;
float y;
float z;
};
float[3] value;
};

// later, in your code
vector v;
v.x = 8.5; // assign a value to x;
v.value[1] = 32.7; // assign a value to y!;



Share this post


Link to post
Share on other sites
you may have a look to the #pragma pack documentation on the msdn for further informations (check here).

Using VC++, what you'll want to do is :

[source lan="cpp"]
// to align struct members a on 1-byte boundary
#pragma pack(push, 1)
struct MyStruct
{
float memberA;
float memberB;
int memberC;
int memberD;
};
#pragma pack(pop)



Then your are sure that you do not have any kind of padding in your structure.

Alternatively, you may use a compiler optino to globaly change the packing alignement of structure members (/Zp1, /Zp2; /Zp4 or /Zp8. The msdn states that the default /Zp is /Zp8).

HTH

Share this post


Link to post
Share on other sites
The ANSI standard defines the offsetof keyword, in <stddef.h>, to get the byte offset of structure members.
Also, the c/C++ compiler will never rearrange the order of data in a structure / class. It would lead to so much broken code, for example:

fwrite (&structure, sizeof structure, 1, file);

just wouldn't be possible.

Skizz

Share this post


Link to post
Share on other sites
For VC on Windows I have found the following rule:

A veriable in a struct must have an offset equal to the multiple of its size.

Allow me to explain:

An int is 32bits (at the moment) so it MUST have an offset (the total bytes that preceeded it, including padding) of either 4, 8, 12 bytes and so on.

A short must be a multiple of 2 (2, 4, 6, 8)

A char can be anywhere. If you break this rule the compiler pads the structure to move the veriable to the correct positon. e.g if you place an int 13 bytes into your structure it will moved to 16 bytes (3 bytes will be inserted before it)

Example


struct Test
{
int V1;
int V2; //this is 4 bytes into the structure, thats ok
char C1; //this ok a char can go anywhere
int V3;// this is wrong. V3 is 9 bytes into the
//the structure. 9 is not a multiple of 4, the next is 12.
//so 3 bytes will be added after C1.
}


Share this post


Link to post
Share on other sites

This topic is 4864 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

Sign in to follow this