Reputation: 5195
I work for a company that uses a large C++ project to automate the manufacturing process and I noticed the following peculiar behavior when looking at the revision history of the C++ source code.
A simplified example of this behavior in the different revisions of the software is shown below.
Revision 1 of software:
struct Foo
{
int x;
int reserve[20]; // unused
};
Revision 2 of software:
struct Foo
{
int x;
int y[2];
int reserve[18]; // unused
};
Revision 3 of software:
struct Foo
{
int x;
int y[2];
int z[5];
int reserve[13]; // unused
};
It is apparent that the unused reserve
array is just there to ensure that any instance of the struct that is created always takes up the same amount of memory, regardless of which revision of the software is running.
My questions are: Is this common practice and/or good practice to do this for large C++ projects? And is there any general (general meaning, non-application-specific) reason that using this practice is required or advantageous?
Upvotes: 2
Views: 228
Reputation: 5195
For what it is worth... I finally (over a year after posting this question) found the exact reason for this:
The program stores this struct
in a shared memory file.
The purpose of keeping this structure in the same format is to preserve the exact memory location of the structure such that any past and future events of the shared memory will still work the same way.
char
s are used as one-byte "buffers" to always keep the struct the same size. The reserve
array is then decreased depending on which datatype is used.
I've also found that a second reserve
array (e.g. reserve2
) is created so that the "jumps" always occur in 4-byte jumps. See below for a visualization of this. The structure always adds up to 100 bytes.
Revision 1:
struct Foo
{
int x; // 4 bytes
char reserve[96]; // 96 bytes
};
Revision 2:
struct Foo
{
int x; // 4 bytes
short y; // 2 bytes
char reserve[94]; // 94 bytes
};
Revision 3:
struct Foo
{
int x; // 4 bytes
short y; // 2 bytes
short reserve2; // 2 bytes (added so that the "jump" is still 4 bytes)
int z; // 4 bytes
char reserve[88]; // 88 bytes
};
Upvotes: 1
Reputation: 1039
Yes, it is a common practice. I can't say if this is a good or bad practice because it depends.
Of course you have to be careful when doing it, since you may run out of reserved fields sometime in the future, often in the places where you'd never expect to.
Upvotes: 7
Reputation: 12413
If the struct you define is sent through network and you don't want to implement some network protocol negotiation, you can in new product versions use struct with more fields used and old version will be still able to receive such structs (as size will not change). It will just ignore the part it is not aware of (treat it as a part of reserve
).
Upvotes: 2