C++ Struct - Define Minimum Size - c++

Is there a C++ (or MSVC) method of automatically padding a struct to a minimum size? For example, imagine the following pseudo-code:
#pragma pad(256) // bytes
struct SETUPDATA {
int var1;
double var2;
};
where sizeof(SETUPDATA) = 256 bytes
The goal here being, during development this struct's members can change without changing the footprint size at runtime.

You can use a union
struct SETUPDATA {
union { struct your_data; char [256]; }
}
or something like this. This ensures it's at least 256 but only as long as your_data is not larger.
You can also add a simple assert after that just does a compiler check assert(sizeof(struct SETUPDATA) == 256)

One way is to inherit from your "real" structure and use sizeof() to make up the padded structure, for example:
struct blah_real
{
int a;
};
struct blah : public blah_real
{
private:
char _pad[256 - sizeof(blah_real)];
};
You could use #ifdef DEBUG to only do this in the debug build and just use the real structure in release build.

The first thing you have ot ask yourself is why your application cares if the struct size changes. That indicate fragility to future changes and your design may be better served by instead allowing the application to seamlessly work in the face of struct size changes.
Perhaps you're trying to serialize the data directly and don't want to face changes in the format, but in that case you're already tying yourself to one specific representation of the structure in memory. For example support the size of one of the builtin-type members changes due to a compiler upgrade or options.
But let's say you really do want to do this.
Just wrap the data in an impl and pad the real struct:
struct SetupData
{
struct Impl
{
int var1;
double var2;
};
Impl impl_;
unsigned char pad_[256 - sizeof(Impl)];
};

Related

Nested array of structs - how do i properly assign a value to struct members?

I have
struct Voice {
static byte mode;
//Some other stuff
};
byte Voice::mode{}; //Static member defined outside of struct declaration
and
struct DataPacket {
DataPacket() : sequencer{}, voice{}, tempdata{} {};
Sequencer sequencer;
Voice voice[4];
Tempdata tempdata;
};
I want to assign one of the voice struct members in the array with a variable value like this:
DataPacket assignVoiceValues(const InputPacket &inputPacket,
DataPacket &dataPacket,
const byte &voiceNumber) {
dataPacket.voice[voiceNumber].mode = (byte) inputPacket.finalPotvalue[0];
//Other code
}
Even though this compiles, when i test the code all of the four structs members mode in the voice[] array are simultaneously assigned with inputPacket.finalPotvalue[0]. There is no code for assigning values to dataPacket.voice[voiceNumber].mode elsewhere that could possibly interfere.
I have no idea why this is happening. What am i missing, and what is the proper syntax for making it work as intended?
(I know vectors generally are recommended over arrays, but the code is intended for an arduino board with limited memory).
You have define mode as static byte mode;... So there's space allocated for exactly one of them in the entire program.
Perhaps mode should not be marked as static?
Since you declare variable "mode" static it is bound to your class (which is single), not to instances of your class (you can create a lot of instances).
To fix the problem just remove static from description of your variable
https://en.cppreference.com/w/cpp/language/static

Templated typedef structs with constructor in C++

I have this code right now, which seems to work so far but I was wondering if there was a way to get the exact same struct in a more elegant way since my method so far needs a duplicate everytime for each struct... The end goal would be to have a typedefed struct which would swap the bytes according to the endianness automatically.
using ResourceHeader_t = struct ResourceHeader_s
{
uint32_t magic;
uint32_t chunkVersion;
uint32_t chunkSize;
};
template<bool bigEndian>
struct ResourceHeader : public ResourceHeader_s
{
ResourceHeader(ResourceHeader_t* ptr) : ResourceHeader_s(*ptr)
{
if (bigEndian)
{
LITTLE_BIG_SWAP(magic);
LITTLE_BIG_SWAP(chunkVersion);
LITTLE_BIG_SWAP(chunkSize);
}
}
};
Usage example :
ResourceHeader<true> resourceHeader((ResourceHeader_t *)fileBuffer);
There is no need for a typedef struct declaration in C++. This is a relic of C.
In C++, after declaring a struct ResourceHeader_s, or struct ResourceHeader_t, or just a plain struct ResourceHeader, the same symbol can be used directly by itself, without an explicit struct.
You might simply add the endianess as a ResourceHeader ctor parameter, rather than a template parameter. This would remove duplicate definitions of the struct (one for big and one not).

Packet cast to struct with multiple dynamic arrays

I'm currently working on a Client/Server application, sending packets via TCP.
To read the incoming packet, I do something like this:
struct SomeRandomStruct
{
int nVal1;
int nVal2;
};
SomeRandomStruct* pStruct = reinterpret_cast<SomeRandomStruct*>(pBuffer);
Right now there's a small problem. Let's say I have a struct like this
struct SomeNewStruct
{
int nNameLen;
int nPassLen;
char szName[];
char szPass[];
};
Since the size/length of szName & szPass is sent in the same packet, is there a way I can set its size ,,within the reinterpret_cast" or do I have to read the packet manually?
Friendly warning:
stop!
Consider something like google protocol buffers to encode messages for you in a cross-platform and safe way.
Here are some reasons why:
How big is an int? On your machine? today? tomorrow? It's undefined in the c++ standard.
What is the binary representation of an int? Is it the same on the machine sending and the machine receiving? Will it always be? (If you think 'yes' then you're wrong). Again the c++ standard has nothing to say on the matter.
What is the padding between data members in the struct? Is it the same for all compilers on all hosts? (answer: no)
ask yourself why functions like htons() exist. They are there because not all machines are the same, but the communication between them must be.
I could go on...
As your question is tagged C++, I'd propose you to do dynamic allocation in constructor and deallocation in destructor. That way, you could have simply pointers in your struct :
struct struct SomeNewStruct {
int nNameLen;
int nPassLen;
char *szName;
char *szPass;
SomeNewStruct(int nameLen , int passLen) {
// set and alloc...
}
SomeNewStruct(SomeNewStruct &src) {
// alloc and copy
}
~SomeNewStruct() {
// dealloc ...
}
}
You could even use std::string for szName and SzPass letting the STL deal with those low level allocation details :
struct struct SomeNewStruct {
int nNameLen;
int nPassLen;
std::string szName;
std::string szPass;
}

Struct offsets differ?

Normally I would have a good smile, but its so sneaky its not even funny.
How the hell can a struct differ from one file to another?
I had a struct like this:
typedef struct pp_sig_s
{
[...]
int flags;
size_t max;
bool is_reversed;
unsigned int sig[64];
size_t byref;
[...]
}
pp_sig_t;
It was defined in say "header01.h"
Some function I use is in "program01.cpp"
Declared this way
void PrintSig(pp_sig_t *s); // prints the content of sig[64] array in pp_sig_t for test purposes
Another object pp_sig_t called g_sig_1 was defined in "header02.cpp"...
This .cpp includes of course header01.h
I call the print routine this way inside it
PrintSig(&g_sig_1);
I notice the print result differs from the actual content.
Say sig contains 0xE8, then it printed 0xE800
Then, I thought, about 2 hours of investigation, it could be struct alignment.
I try it...
Declaring the struct this way in header01.h
#pragma push()
#pragma pack(4)
typedef struct pp_sig_s
{
[...]
int flags;
size_t max;
bool is_reversed;
unsigned int sig[64];
size_t byref;
[...]
}
pp_sig_t;
#pragma pop()
And suddenly everything works fine...
So basically its like if in program01.cpp the struct offsets were, i would guess, different than in program02.cpp...
How the hell can a struct differs from one file to another? How can we avoid this without using pragmas? Could it be called a compiler bug (i use Intel C++ XE Composer 2013 Update 2, on linux)?
It seems likely that this was caused by an alignment pragma that was in scope when one of the files included the header, but not when the other did.

Is there any way to prepare a struct for future additions?

I have the following struct which will be used to hold plugin information. I am very sure this will change (added to most probably) over time. Is there anything better to do here than what I have done assuming that this file is going to be fixed?
struct PluginInfo
{
public:
std::string s_Author;
std::string s_Process;
std::string s_ReleaseDate;
//And so on...
struct PluginVersion
{
public:
std::string s_MajorVersion;
std::string s_MinorVersion;
//And so on...
};
PluginVersion o_Version;
//For things we aren't prepared for yet.
void* p_Future;
};
Further, is there any precautions I should take when building shared objects for this system. My hunch is I'll run into lots of library incompatibilities. Please help. Thanks
What about this, or am I thinking too simple?
struct PluginInfo2: public PluginInfo
{
public:
std::string s_License;
};
In your application you are probably passing around only pointers to PluginInfos, so version 2 is compatible to version 1. When you need access to the version 2 members, you can test the version with either dynamic_cast<PluginInfo2 *> or with an explicit pluginAPIVersion member.
Either your plugin is compiled with the same version of C++ compiler and std library source (or its std::string implementation may not be compatible, and all your string fields will break), in which case you have to recompile the plugins anyway, and adding fields to the struct won't matter
Or you want binary compatibility with previous plugins, in which case stick to plain data and fixed size char arrays ( or provide an API to allocate the memory for the strings based on size or passing in a const char* ), in which case it's not unheard of to have a few unused fields in the struct, and then change these to be usefully named items when the need arises. In such cases, it's also common to have a field in the struct to say which version it represents.
But it's very rare to expect binary compatibility and make use of std::string. You'll never be able to upgrade or change your compiler.
As was said by someone else, for binary compatibility you will most likely restrict yourself to a C API.
The Windows API in many places maintains binary compatibility by putting a size member into the struct:
struct PluginInfo
{
std::size_t size; // should be sizeof(PluginInfo)
const char* s_Author;
const char* s_Process;
const char* s_ReleaseDate;
//And so on...
struct PluginVersion
{
const char* s_MajorVersion;
const char* s_MinorVersion;
//And so on...
};
PluginVersion o_Version;
};
When you create such a beast, you need to set the size member accordingly:
PluginInfo pluginInfo;
pluginInfo.size = sizeof(pluginInfo);
// set other members
When you compile your code against a newer version of the API, where the struct has additional members, its size changes, and that is noted in its size member. The API functions, when being passed such a struct presumably will first read its size member and branch into different ways to handle the struct, depending on its size.
Of course, this assumes that evolution is linear and new data is always only added at the end of the struct. That is, you will never have different versions of such a type that have the same size.
However, using such a beast is a nice way of ensuring that user introduce errors into their code. When they re-compile their code against a new API, sizeof(pluginInfo) will automatically adapt, but the additional members won't be set automatically. A reasonably safety would be gained by "initializing" the struct the C way:
PluginInfo pluginInfo;
std::memset( &pluginInfo, 0, sizeof(pluginInfo) );
pluginInfo.size = sizeof(pluginInfo);
However, even putting aside the fact that, technically, zeroing memory might not put a reasonable value into each member (for example, there could be architectures where all bits set to zero is not a valid value for floating point types), this is annoying and error-prone because it requires three-step construction.
A way out would be to design a small and inlined C++ wrapper around that C API. Something like:
class CPPPluginInfo : PluginInfo {
public:
CPPPluginInfo()
: PluginInfo() // initializes all values to 0
{
size = sizeof(PluginInfo);
}
CPPPluginInfo(const char* author /* other data */)
: PluginInfo() // initializes all values to 0
{
size = sizeof(PluginInfo);
s_Author = author;
// set other data
}
};
The class could even take care of storing the strings pointed to by the C struct's members in a buffer, so that users of the class wouldn't even have to worry about that.
Edit: Since it seems this isn't as clear-cut as I thought it is, here's an example.
Suppose that very same struct will in a later version of the API get some additional member:
struct PluginInfo
{
std::size_t size; // should be sizeof(PluginInfo)
const char* s_Author;
const char* s_Process;
const char* s_ReleaseDate;
//And so on...
struct PluginVersion
{
const char* s_MajorVersion;
const char* s_MinorVersion;
//And so on...
};
PluginVersion o_Version;
int fancy_API_version2_member;
};
When a plugin linked to the old version of the API now initializes its struct like this
PluginInfo pluginInfo;
pluginInfo.size = sizeof(pluginInfo);
// set other members
its struct will be the old version, missing the new and shiny data member from version 2 of the API. If it now calls a function of the second API accepting a pointer to PluginInfo, it will pass the address of an old PluginInfo, short one data member, to the new API's function. However, for the version 2 API function, pluginInfo->size will be smaller than sizeof(PluginInfo), so it will be able catch that, and treat the pointer as pointing to an object that doesn't have the fancy_API_version2_member. (Presumably, internal of the host app's API, PluginInfo is the new and shiny one with the fancy_API_version2_member, and PluginInfoVersion1 is the new name of the old type. So all the new API needs to do is to cast the PluginInfo* it got handed be the plugin into a PluginInfoVersion1* and branch off to code that can deal with that dusty old thing.)
The other way around would be a plugin compiled against the new version of the API, where PluginInfo contains the fancy_API_version2_member, plugged into an older version of the host app that knows nothing about it. Again, the host app's API functions can catch that by checking whether pluginInfo->size is greater than the sizeof their own PluginInfo. If so, the plugin presumably was compiled against a newer version of the API than the host app knows about. (Or the plugin write failed to properly initialize the size member. See below for how to simplify dealing with this somewhat brittle scheme.)
There's two ways to deal with that: The simplest is to just refuse to load the plugin. Or, if possible, the host app could work with this anyhow, simply ignoring the binary stuff at the end of the PluginInfo object it was passed which it doesn't know how to interpret.
However, the latter is tricky, since you need to decide this when you implement the old API, without knowing exactly what the new API will look like.
what rwong suggest (std::map<std::string, std::string>) is a good direction. This is makes it possible to add deliberate string fields. If you want to have more flexibility you might declare an abstract base class
class AbstractPluginInfoElement { public: virtual std::string toString() = 0;};
and
class StringPluginInfoElement : public AbstractPluginInfoElement
{
std::string m_value;
public:
StringPluginInfoElement (std::string value) { m_value = value; }
virtual std::string toString() { return m_value;}
};
You might then derive more complex classes like PluginVersion etc. and store a map<std::string, AbstractPluginInfoElement*>.
One hideous idea:
A std::map<std::string, std::string> m_otherKeyValuePairs; would be enough for the next 500 years.
Edit:
On the other hand, this suggestion is so prone to misuse that it may qualify for a TDWTF.
Another equally hideous idea:
a std::string m_everythingInAnXmlBlob;, as seen in real software.
(hideous == not recommended)
Edit 3:
Advantage: The std::map member is not subject to object slicing. When older source code copies an PluginInfo object that contains new keys in the property bag, the entire property bag is copied.
Disadvantage: many programmers will start adding unrelated things to the property bag, and even starts writing code that processes the values in the property bag, leading to maintenance nightmare.
Here's an idea, not sure whether it works with classes, it for sure works with structs: You can make the struct "reserve" some space to be used in the future like this:
struct Foo
{
// Instance variables here.
int bar;
char _reserved[128]; // Make the class 128 bytes bigger.
}
An initializer would zero out whole struct before filling it, so newer versions of the class which would access fields that would now be within the "reserved" area are of sane default values.
If you only add fields in front of _reserved, reducing its size accordingly, and not modify/rearrange other fields you should be OK. No need for any magic. Older software will not touch the new fields as they don't know about them, and the memory footprint will remain the same.