I'm using the Code::Blocks IDE with the GNU GCC compiler.
struct test
{
char a;
char e;
char f;
char b;
char d;
};
sizeof(test) returns 5.
I read this answer:
Why isn't sizeof for a struct equal to the sum of sizeof of each member?
How come there is no padding after the last char, so that sizeof(test) returns 6 or 8? There are a ton more questions I could ask once I add short and int, etc. But I think this question is good for now. Would not padding make it easier for the processor to work with the struct?
The alignment of a char is only 1, so there is no need for the struct to be padded out to meet a larger alignment requirement.
Since at most times you work with one member at time, or pass the address of the struct, the compiler doesn't care to align the whole struct more than the alignment needed for its members. That means that if you assign this struct (or pass it to function), the processor will have to read it member-by-member. (and it will be a little slowly).
Related
Reading Rapidjson code I found some interesting optimization with "type punning".
// By using proper binary layout, retrieval of different integer types do not need conversions.
union Number {
#if RAPIDJSON_ENDIAN == RAPIDJSON_LITTLEENDIAN
struct I {
int i;
char padding[4];
}i;
struct U {
unsigned u;
char padding2[4];
}u;
#else
struct I {
char padding[4];
int i;
}i;
struct U {
char padding2[4];
unsigned u;
}u;
#endif
int64_t i64;
uint64_t u64;
double d;
}; // 8 bytes
It looks like only BE CPUs are affected by this optimization. How does this increases performance? I'd like to test but do not have BE machine.
Wikipedia says:
While not allowed by C++, such type punning code is allowed as "implementation-defined" by the C11 standard[15] and commonly used[16] in code interacting with hardware.[17]
So is it legal in C++? I believe in absolute most cases it works fine. But should I use it in new code?
So is it legal in C++?
No, it isn't legal in c++ (Wikipedia also already stated "While not allowed by C++ ...").
In c++ a union is just reserving memory for the contained union members, such that it is enough to fit the largest member. That memory is shared by all members.
Accessing a different member from the union as was used to initialize it, is undefined behavior. You need to decide beforehand with which union members to work, if these are shared by any functions (this is often done using a type discriminator).
I am not sure the question is well put, because I understood how, but I don't know to write the questions with the thing I don't understand. Here it is:
I have some classes:
class Animal{};
class Rabbit{}: public Animal;
class Horse{}: public Animal;
class Mouse{}: public Animal;
class Pony{}: public Horse;
My goal was to find the maximum size from this object list in order to use it in memory allocation afterwards. I've stored each sizeof of the object in an array then took the max of the array. The superior(to whom I send the code for review) suggested me to use an union in order to find maximum size at pre-compilation time. The idea seemed very nice to me so I've did it like this:
typedef union
{
Rabbit rabbitObject;
Horse horseObject;
Mouse mouseObject;
Pony ponyObject;
} Size;
... because an union allocates memory according to the greatest-in-size element.
The next suggestion was to do it like this:
typedef union
{
unsigned char RabbitObject[sizeof(Rabbit)];
unsigned char HorseObject[sizeof(Horse)];
unsigned char MouseObject[sizeof(Mouse)];
unsigned char PonyObject[sizeof(Pony)];
} Interesting;
My question is:
How does Interesting union get the maximum size of object? To me, it makes no sense to create an array of type unsigned char, of length sizeof(class) inside it. Why the second option would solve the problem and previous union it doesn't?
What's happening behind and I miss?
PS: The conditions are in that way that I cannot ask the guy personally.
Thank you in advance
The assumptions are incorrect, and the question is moot. Standard does not require the union size to be equal of the size of the largest member. Instead, it requires union size to be sufficient to hold the largest member, which is not the same at all. Both solutions are flawed is size of the largest class needs to be known exactly.
Instead, something like that should be used:
template<class L, class Y, class... T> struct max_size
: std::integral_constant<size_t, std::max(sizeof (L), max_size<Y, T...>::value)> { };
template<class L, class Y> struct max_size<L, Y>
: std::integral_constant<size_t, std::max(sizeof (L), sizeof (Y))> { };
As #Caleth suggested below, it could be shortened using initializer list version of std::max (and template variables):
template<class... Ts>
constexpr size_t max_size_v = std::max({sizeof(Ts)...});
The two approaches provide a way to find a maximum size that all of the objects of the union will fit within. I would prefer the first as it is clearer as to what is being done and the second provides nothing that the first does not for your needs.
And the first, a union composed of the various classes, offers the ability to access a specific member of the union as well.
See also Is a struct's address the same as its first member's address?
as well as sizeof a union in C/C++
and Anonymous union and struct [duplicate]
.
For some discussions on memory layout of classes see the following postings:
Structure of a C++ Object in Memory Vs a Struct
How is the memory layout of a class vs. a struct
memory layout C++ objects [closed]
C++ Class Memory Model And Alignment
What does an object look like in memory? [duplicate]
C++11 introduced a standardized memory model. What does it mean? And how is it going to affect C++ programming?
Since the compiler is free to add to the sizes of the various components in order to align variables on particular memory address boundaries, the size of the union may be larger than the actual size of the data. Some compilers offer a pragma or other type of directive to instruct the compiler as to whether packing of the class, struct, or union members should be done or not.
The size as reported by sizeof() will be the size of the variable or type specified however again this may include additional unused memory area to pad the variable to the next desirable memory address alignment. See Why isn't sizeof for a struct equal to the sum of sizeof of each member?.
Typically a class, struct, or union is sized so that if an array of the type is created then each element of the array will begin on the most useful memory alignment such as a double word memory alignment for an Intel x86 architecture. This padding is typically on the end of the variable.
You superior suggested you use the array version because a union could have padding. For instance if you have
union padding {
char arr[sizeof (double) + 1];
double d;
};
The this could either be of size sizeof(double) + 1 or it could be sizeof (double) * 2 as the union could be padded to keep it aligned for double's (Live example).
However if you have
union padding {
char arr[sizeof(double) + 1];
char d[sizeof(double)];
};
The the union need not be double aligned and the union most likely has a size of sizeof(double) + 1 (Live example). This is not guanrteed though and the size can be greater than it's largest element.
If you want for sure to have largest size I would suggest using
auto max_size = std::max({sizeof(Rabbit), sizeof(Horse), sizeof(Mouse), sizeof(Pony)});
when we're talking about alignment we're always referring to variables inside a struct and not to single variables.
could you please tell me why is that?
when we're referring to a variable , would it take the whole size of "word"?
Most likely because if you're messing with variable alignement you are either in the world of low level optimisation (based on cache line estimations and whatnot) or doing some embed programming.
Most developers don't do that and the ones who do are more likely to go read their plateforme specs and rethink about the alignement principles that they probably already know rather than discuss it on internet (there are exceptions of course, it's just not the general tendency).
I have yet to see a variable alignement which is not a derivate of:
// the array "cacheline" will be aligned to 128-byte boundary
alignas(128) char cacheline[128];
On the other hand you don't need very specific situations to see the impact of aggregate(struct) alignement on a program.
This is something a beginner will write and question at some point or another:
#include <iostream>
struct no_align
{
char c;
double d;
int i;
};
struct align
{
double d;
int i;
char c;
};
int main(void)
{
no_align no_align_array[100];
align align_array[100];
std::cout << sizeof(no_align_array) << std::endl;
std::cout << sizeof(align_array) << std::endl;
}
On my machine the result is:
2400
1600
And that's the point where you'll go around on internet asking why in the world one version makes you use 800 more bytes than the other if no teacher ever explained that to you.
Every type has a size, which is fixed, and an alignment requirement.
A struct has members with their own alignment requirements. As a logical consequence, a struct must have an alignment requirement at least as strong as those of all its members. A struct may have to add padding so that all its members meet their alignment requirements.
An array stores multiple array elements consecutively without any padding. As a logical consequence, the size of any type must be a multiple of its alignment requirement (so a struct containing an int and a char cannot have an alignment requirement of four bytes and a size of five bytes, because that wouldn't work for the second array element in an array of two such structs).
Variables need to have addresses so their alignment requirements are satisfied, so your first sentence is wrong.
However, there is the "as-if" rule: Normally, the compiler has to do what the language tells it. But the "as-if" rule says that the compiler can do whatever it wants to do as long as a program cannot find the difference. So if storing an int on an unaligned address makes no difference (except maybe a tiny cost in time), the compiler is allowed to do this.
Is there guarantee, that memory for this object will be properly aligned if we create object of this type in stack?
union my_union
{
int value;
char bytes[4];
};
If we create char bytes[4] in stack and then try to cast it to integer there might be alignment problem. We can avoid that problem by creating it in heap, however, is there such guarantee for union objects? Logically there should be, but I would like to confirm.
Thanks.
Well, that depends on what you mean.
If you mean:
Will both the int and char[4] members of the union be properly aligned so that I may use them independently of each other?
Then yes. If you mean:
Will the int and char[4] members be guaranteed to be aligned to take up the same amount of space, so that I may access individual bytes of the int through the char[4]?
Then no. This is because sizeof(int) is not guaranteed to be 4. If ints are 2 bytes, then who knows which two char elements will correspond to the int in your union (the standard doesn't specify)?
If you want to use a union to access the individual bytes of an int, use this:
union {
int i;
char c[sizeof(int)];
};
Since each member is the same size, they're guaranteed to occupy the same space. This is what I believe you want to know about, and I hope I've answered it.
Yeah, unions would be utterly useless otherwise.
What does the warning "alignment of a member was sensitive to packing" mean in C++? I'm using Visual Studio 2005.
How do I go about removing these warnings? I don't want to disable them btw.
Some data types must be aligned to a certain boundary. So for example:
struct V
{
char a;
double b;
char c;
double d;
};
sizeof(char) is 1 and sizeof(double) is 8 but the size of that struct may be more than the expected 18 if it needs the doubles to align to an 8-byte boundary. In that case, and because the members should appear in memory in the order they are declared in the struct, there may be 7 bytes of "padding" close to the member c, and possibly some with member a too.
The danger here comes when the packing is non-standard so the size of this struct could vary, and you send it in "binary" format over a wire or store it in a file where it will be read elsewhere (even if the endian-ness of the double is the same).
As an alternative to the suggestions to remove the warning through pragmas, you might decide to deal with it in the code by changing the order of your members. Put those that need the biggest alignment first, and the lower ones later. So first put pointers and doubles, then ints, then shorts and any char members last.
Taken from MSDN -
'symbol' : alignment of a member was sensitive to packing
A structure member is aligned on a memory offset whose value is not a multiple of the member's size. For example, the following code snippet will produce this warning:
// C4121.cpp
// compile with: /W4 /c
#pragma pack(2) // C4121
struct s
{
char a;
int b;
};
You could make one of the following changes to prevent this warning:
Change pack(2) to pack(4).
Reverse the order of the structure members such that the int precedes the char.
When data is not aligned on boundaries that are multiples of the data's size performance can degrade and if you port your code to a RISC machine it will not compile.
You can specify the structure alignment with #pragma pack or /Zp. Note that the compiler does not generate this warning when /Zp1 is specified.