How to organize members in a struct to waste least space on alignment?Are there performance issues when using pragma pack(1)?Why isn't sizeof for a struct equal to the sum of sizeof of each member?new[] expression does not respect alignment in Microsoft VC++Why can't C compilers rearrange struct members to eliminate alignment padding?Memory layout mismatching between CPU and GPU code with CUDAC++ struct aligment to 1 byte causes crash on WinCEIs there a way to guarantee alignment of members of a malloc()-ed structsHow does CUDA's nppiMalloc… function guarantee alignment?Optimally packing a recursively templated struct without loss of alignmentR_alloc and alignment considerationsHow does aligning memory in a custom double ended stack-based allocator work?
Was it really unprofessional of me to leave without asking for a raise first?
How can my story take place on Earth without referring to our existing cities and countries?
Movie in a trailer park named Paradise and a boy playing a video game then being recruited by aliens to fight in space
How can I deal with extreme temperatures in a hotel room?
Meaning of じゃないんじゃない?
Is it bad to describe a character long after their introduction?
For decoupling an IC's power supply pins, is there any reason to use multiple capacitances when all the MLCCs have the same package size?
Ordered list of OR journals
Who are these Discworld wizards from this picture?
Different budgets within roommate group
How did researchers find articles before the Internet and the computer era?
Losing queen and then winning the game
Should I report a leak of confidential HR information?
Why does the same classical piece sound like it's in a different key in different recordings?
What exactly did Ant-Man see that made him say that their plan worked?
What does grep -v "grep" mean and do?
Sharing referee/AE report online to point out a grievous error in refereeing
Golf the smallest circle!
Who voices the character "Finger" in The Fifth Element?
What's the safest way to inform a new user of their password on an invite-only website?
Why were the first airplanes "backwards"?
How is this practical and very old scene shot?
Do launching rockets produce a sonic boom?
Step into the Octagram
How to organize members in a struct to waste least space on alignment?
Are there performance issues when using pragma pack(1)?Why isn't sizeof for a struct equal to the sum of sizeof of each member?new[] expression does not respect alignment in Microsoft VC++Why can't C compilers rearrange struct members to eliminate alignment padding?Memory layout mismatching between CPU and GPU code with CUDAC++ struct aligment to 1 byte causes crash on WinCEIs there a way to guarantee alignment of members of a malloc()-ed structsHow does CUDA's nppiMalloc… function guarantee alignment?Optimally packing a recursively templated struct without loss of alignmentR_alloc and alignment considerationsHow does aligning memory in a custom double ended stack-based allocator work?
.everyoneloves__top-leaderboard:empty,.everyoneloves__mid-leaderboard:empty,.everyoneloves__bot-mid-leaderboard:empty margin-bottom:0;
I have just realized how much memory is wasted as a result of alignment in C++. Consider the following simple example:
struct X
int a;
double b;
int c;
;
int main()
cout << "sizeof(int) = " << sizeof(int) << 'n';
cout << "sizeof(double) = " << sizeof(double) << 'n';
cout << "2 * sizeof(int) + sizeof(double) = " << 2 * sizeof(int) + sizeof(double) << 'n';
cout << "but sizeof(X) = " << sizeof(X) << 'n';
When using g++ the program gives the following output:
sizeof(int) = 4
sizeof(double) = 8
2 * sizeof(int) + sizeof(double) = 16
but sizeof(X) = 24
That's 50% memory overhead! In a 3-gigabyte array of 134'217'728 X
s 1 gigabyte would be pure padding.
Fortunately, the solution to the problem is very simple - we simply have to swap double b
and int c
around:
struct X
int a;
int c;
double b;
;
Now the result is much more satisfying:
sizeof(int) = 4
sizeof(double) = 8
2 * sizeof(int) + sizeof(double) = 16
but sizeof(X) = 16
There is however a problem: this isn't cross-compatible. Yes, under g++ an int
is 4 bytes and a double
is 8 bytes, but that's not necessarily always true (their alignment doesn't have to be the same either), so under a different environment this "fix" could not only be useless, but could also potentially make things worse by increasing the amount of padding needed.
Is there a reliable cross-platform way to solve this problem (minimize the amount of needed padding without suffering from decreased performance caused by misalignment)? Why doesn't the compiler perform such optimizations (swap struct/class members around to decrease padding)?
EDIT
Due to misunderstanding and confusion, I'd like to emphasize that I don't want to "pack" my struct
. I still want it to be aligned, but in a way that uses the least memory on padding.
c++ optimization memory-alignment memory-layout struct-member-alignment
|
show 2 more comments
I have just realized how much memory is wasted as a result of alignment in C++. Consider the following simple example:
struct X
int a;
double b;
int c;
;
int main()
cout << "sizeof(int) = " << sizeof(int) << 'n';
cout << "sizeof(double) = " << sizeof(double) << 'n';
cout << "2 * sizeof(int) + sizeof(double) = " << 2 * sizeof(int) + sizeof(double) << 'n';
cout << "but sizeof(X) = " << sizeof(X) << 'n';
When using g++ the program gives the following output:
sizeof(int) = 4
sizeof(double) = 8
2 * sizeof(int) + sizeof(double) = 16
but sizeof(X) = 24
That's 50% memory overhead! In a 3-gigabyte array of 134'217'728 X
s 1 gigabyte would be pure padding.
Fortunately, the solution to the problem is very simple - we simply have to swap double b
and int c
around:
struct X
int a;
int c;
double b;
;
Now the result is much more satisfying:
sizeof(int) = 4
sizeof(double) = 8
2 * sizeof(int) + sizeof(double) = 16
but sizeof(X) = 16
There is however a problem: this isn't cross-compatible. Yes, under g++ an int
is 4 bytes and a double
is 8 bytes, but that's not necessarily always true (their alignment doesn't have to be the same either), so under a different environment this "fix" could not only be useless, but could also potentially make things worse by increasing the amount of padding needed.
Is there a reliable cross-platform way to solve this problem (minimize the amount of needed padding without suffering from decreased performance caused by misalignment)? Why doesn't the compiler perform such optimizations (swap struct/class members around to decrease padding)?
EDIT
Due to misunderstanding and confusion, I'd like to emphasize that I don't want to "pack" my struct
. I still want it to be aligned, but in a way that uses the least memory on padding.
c++ optimization memory-alignment memory-layout struct-member-alignment
If you need "arrays" of hundreds of millions of elements, then perhaps arrays is not the correct data-structure to begin with? At least not in-memory arrays (think memory mapped files, or perhaps even some kind of database)?
– Some programmer dude
9 hours ago
And really, the only possible answer to the question "[i]s there a reliable cross-platform way to solve this problem (minimize the amount of needed padding without suffering from decreased performance caused by misalignment)?" could only be a simple "no". There are probably compiler and system specific ways to work around it, but nothing truly portable or compiler/platform/system agnostic.
– Some programmer dude
9 hours ago
1
May be some portability benefits from using fixed width integers so they don't change size on you.
– user4581301
9 hours ago
3
largest alignment requirements first. If none, then largest members first. Regarding your real question, yes there is a cross-compatible method for doing this: it's called a string. Outside of that, types using specified bit widths can help significantly, but still require endian handling if you're really serious about cross platform. In short, protocols exist specifically to address such issues and bridge the hard differences between platforms. Things like this are one of many reasons why they exist, Caveat: Good chance I completely misunderstood the "this" of this question.
– WhozCraig
9 hours ago
1
For all the reasons above, there is no one thing that guarantees a minimum storage for struct size, but @WhozCraig provides a precise explanation of the oversimplified rule Biggest First, Smallest Last in decreasing order of storage size required. That's about as reasonable an approach likely to minimize storage across compilers and hardware, but there is no guarantee any two structs will be allocated the same amount of storage between compilers (other than trivial examples (such asstruct foo int a, b; ;
)
– David C. Rankin
8 hours ago
|
show 2 more comments
I have just realized how much memory is wasted as a result of alignment in C++. Consider the following simple example:
struct X
int a;
double b;
int c;
;
int main()
cout << "sizeof(int) = " << sizeof(int) << 'n';
cout << "sizeof(double) = " << sizeof(double) << 'n';
cout << "2 * sizeof(int) + sizeof(double) = " << 2 * sizeof(int) + sizeof(double) << 'n';
cout << "but sizeof(X) = " << sizeof(X) << 'n';
When using g++ the program gives the following output:
sizeof(int) = 4
sizeof(double) = 8
2 * sizeof(int) + sizeof(double) = 16
but sizeof(X) = 24
That's 50% memory overhead! In a 3-gigabyte array of 134'217'728 X
s 1 gigabyte would be pure padding.
Fortunately, the solution to the problem is very simple - we simply have to swap double b
and int c
around:
struct X
int a;
int c;
double b;
;
Now the result is much more satisfying:
sizeof(int) = 4
sizeof(double) = 8
2 * sizeof(int) + sizeof(double) = 16
but sizeof(X) = 16
There is however a problem: this isn't cross-compatible. Yes, under g++ an int
is 4 bytes and a double
is 8 bytes, but that's not necessarily always true (their alignment doesn't have to be the same either), so under a different environment this "fix" could not only be useless, but could also potentially make things worse by increasing the amount of padding needed.
Is there a reliable cross-platform way to solve this problem (minimize the amount of needed padding without suffering from decreased performance caused by misalignment)? Why doesn't the compiler perform such optimizations (swap struct/class members around to decrease padding)?
EDIT
Due to misunderstanding and confusion, I'd like to emphasize that I don't want to "pack" my struct
. I still want it to be aligned, but in a way that uses the least memory on padding.
c++ optimization memory-alignment memory-layout struct-member-alignment
I have just realized how much memory is wasted as a result of alignment in C++. Consider the following simple example:
struct X
int a;
double b;
int c;
;
int main()
cout << "sizeof(int) = " << sizeof(int) << 'n';
cout << "sizeof(double) = " << sizeof(double) << 'n';
cout << "2 * sizeof(int) + sizeof(double) = " << 2 * sizeof(int) + sizeof(double) << 'n';
cout << "but sizeof(X) = " << sizeof(X) << 'n';
When using g++ the program gives the following output:
sizeof(int) = 4
sizeof(double) = 8
2 * sizeof(int) + sizeof(double) = 16
but sizeof(X) = 24
That's 50% memory overhead! In a 3-gigabyte array of 134'217'728 X
s 1 gigabyte would be pure padding.
Fortunately, the solution to the problem is very simple - we simply have to swap double b
and int c
around:
struct X
int a;
int c;
double b;
;
Now the result is much more satisfying:
sizeof(int) = 4
sizeof(double) = 8
2 * sizeof(int) + sizeof(double) = 16
but sizeof(X) = 16
There is however a problem: this isn't cross-compatible. Yes, under g++ an int
is 4 bytes and a double
is 8 bytes, but that's not necessarily always true (their alignment doesn't have to be the same either), so under a different environment this "fix" could not only be useless, but could also potentially make things worse by increasing the amount of padding needed.
Is there a reliable cross-platform way to solve this problem (minimize the amount of needed padding without suffering from decreased performance caused by misalignment)? Why doesn't the compiler perform such optimizations (swap struct/class members around to decrease padding)?
EDIT
Due to misunderstanding and confusion, I'd like to emphasize that I don't want to "pack" my struct
. I still want it to be aligned, but in a way that uses the least memory on padding.
c++ optimization memory-alignment memory-layout struct-member-alignment
c++ optimization memory-alignment memory-layout struct-member-alignment
edited 9 hours ago
NathanOliver
106k19 gold badges159 silver badges235 bronze badges
106k19 gold badges159 silver badges235 bronze badges
asked 9 hours ago
Yan B.Yan B.
35112 bronze badges
35112 bronze badges
If you need "arrays" of hundreds of millions of elements, then perhaps arrays is not the correct data-structure to begin with? At least not in-memory arrays (think memory mapped files, or perhaps even some kind of database)?
– Some programmer dude
9 hours ago
And really, the only possible answer to the question "[i]s there a reliable cross-platform way to solve this problem (minimize the amount of needed padding without suffering from decreased performance caused by misalignment)?" could only be a simple "no". There are probably compiler and system specific ways to work around it, but nothing truly portable or compiler/platform/system agnostic.
– Some programmer dude
9 hours ago
1
May be some portability benefits from using fixed width integers so they don't change size on you.
– user4581301
9 hours ago
3
largest alignment requirements first. If none, then largest members first. Regarding your real question, yes there is a cross-compatible method for doing this: it's called a string. Outside of that, types using specified bit widths can help significantly, but still require endian handling if you're really serious about cross platform. In short, protocols exist specifically to address such issues and bridge the hard differences between platforms. Things like this are one of many reasons why they exist, Caveat: Good chance I completely misunderstood the "this" of this question.
– WhozCraig
9 hours ago
1
For all the reasons above, there is no one thing that guarantees a minimum storage for struct size, but @WhozCraig provides a precise explanation of the oversimplified rule Biggest First, Smallest Last in decreasing order of storage size required. That's about as reasonable an approach likely to minimize storage across compilers and hardware, but there is no guarantee any two structs will be allocated the same amount of storage between compilers (other than trivial examples (such asstruct foo int a, b; ;
)
– David C. Rankin
8 hours ago
|
show 2 more comments
If you need "arrays" of hundreds of millions of elements, then perhaps arrays is not the correct data-structure to begin with? At least not in-memory arrays (think memory mapped files, or perhaps even some kind of database)?
– Some programmer dude
9 hours ago
And really, the only possible answer to the question "[i]s there a reliable cross-platform way to solve this problem (minimize the amount of needed padding without suffering from decreased performance caused by misalignment)?" could only be a simple "no". There are probably compiler and system specific ways to work around it, but nothing truly portable or compiler/platform/system agnostic.
– Some programmer dude
9 hours ago
1
May be some portability benefits from using fixed width integers so they don't change size on you.
– user4581301
9 hours ago
3
largest alignment requirements first. If none, then largest members first. Regarding your real question, yes there is a cross-compatible method for doing this: it's called a string. Outside of that, types using specified bit widths can help significantly, but still require endian handling if you're really serious about cross platform. In short, protocols exist specifically to address such issues and bridge the hard differences between platforms. Things like this are one of many reasons why they exist, Caveat: Good chance I completely misunderstood the "this" of this question.
– WhozCraig
9 hours ago
1
For all the reasons above, there is no one thing that guarantees a minimum storage for struct size, but @WhozCraig provides a precise explanation of the oversimplified rule Biggest First, Smallest Last in decreasing order of storage size required. That's about as reasonable an approach likely to minimize storage across compilers and hardware, but there is no guarantee any two structs will be allocated the same amount of storage between compilers (other than trivial examples (such asstruct foo int a, b; ;
)
– David C. Rankin
8 hours ago
If you need "arrays" of hundreds of millions of elements, then perhaps arrays is not the correct data-structure to begin with? At least not in-memory arrays (think memory mapped files, or perhaps even some kind of database)?
– Some programmer dude
9 hours ago
If you need "arrays" of hundreds of millions of elements, then perhaps arrays is not the correct data-structure to begin with? At least not in-memory arrays (think memory mapped files, or perhaps even some kind of database)?
– Some programmer dude
9 hours ago
And really, the only possible answer to the question "[i]s there a reliable cross-platform way to solve this problem (minimize the amount of needed padding without suffering from decreased performance caused by misalignment)?" could only be a simple "no". There are probably compiler and system specific ways to work around it, but nothing truly portable or compiler/platform/system agnostic.
– Some programmer dude
9 hours ago
And really, the only possible answer to the question "[i]s there a reliable cross-platform way to solve this problem (minimize the amount of needed padding without suffering from decreased performance caused by misalignment)?" could only be a simple "no". There are probably compiler and system specific ways to work around it, but nothing truly portable or compiler/platform/system agnostic.
– Some programmer dude
9 hours ago
1
1
May be some portability benefits from using fixed width integers so they don't change size on you.
– user4581301
9 hours ago
May be some portability benefits from using fixed width integers so they don't change size on you.
– user4581301
9 hours ago
3
3
largest alignment requirements first. If none, then largest members first. Regarding your real question, yes there is a cross-compatible method for doing this: it's called a string. Outside of that, types using specified bit widths can help significantly, but still require endian handling if you're really serious about cross platform. In short, protocols exist specifically to address such issues and bridge the hard differences between platforms. Things like this are one of many reasons why they exist, Caveat: Good chance I completely misunderstood the "this" of this question.
– WhozCraig
9 hours ago
largest alignment requirements first. If none, then largest members first. Regarding your real question, yes there is a cross-compatible method for doing this: it's called a string. Outside of that, types using specified bit widths can help significantly, but still require endian handling if you're really serious about cross platform. In short, protocols exist specifically to address such issues and bridge the hard differences between platforms. Things like this are one of many reasons why they exist, Caveat: Good chance I completely misunderstood the "this" of this question.
– WhozCraig
9 hours ago
1
1
For all the reasons above, there is no one thing that guarantees a minimum storage for struct size, but @WhozCraig provides a precise explanation of the oversimplified rule Biggest First, Smallest Last in decreasing order of storage size required. That's about as reasonable an approach likely to minimize storage across compilers and hardware, but there is no guarantee any two structs will be allocated the same amount of storage between compilers (other than trivial examples (such as
struct foo int a, b; ;
)– David C. Rankin
8 hours ago
For all the reasons above, there is no one thing that guarantees a minimum storage for struct size, but @WhozCraig provides a precise explanation of the oversimplified rule Biggest First, Smallest Last in decreasing order of storage size required. That's about as reasonable an approach likely to minimize storage across compilers and hardware, but there is no guarantee any two structs will be allocated the same amount of storage between compilers (other than trivial examples (such as
struct foo int a, b; ;
)– David C. Rankin
8 hours ago
|
show 2 more comments
4 Answers
4
active
oldest
votes
gcc has the -Wpadded
warning that warns when padding is added to a structure:
https://godbolt.org/z/iwO5Q3:
<source>:4:12: warning: padding struct to align 'X::b' [-Wpadded]
4 | double b;
| ^
<source>:1:8: warning: padding struct size to alignment boundary [-Wpadded]
1 | struct X
| ^
And you can manually rearrange members so that there is less / no padding. But this is not a cross platform solution, as different types can have different sizes / alignments on different system (Most notably pointers being 4 or 8 bytes on different architectures). The general rule of thumb is go from largest to smallest alignment when declaring members, and if you're still worried, compile your code with -Wpadded
once (But I wouldn't keep it on generally, because padding is necessary sometimes).
As for the reason why the compiler can't do it automatically is because of the standard ([class.mem]/19). It guarantees that, because this is a simple struct with only public members, &x.a < &x.c
(for some X x;
), so they can't be rearranged.
1
I honestly didn't think I'd see something useful come out of this question. Wasn't aware of that gcc option (and now I'm hopign clang has it as well). Thanks for teaching me something. tick.
– WhozCraig
9 hours ago
add a comment |
There really isn't a portable solution in the generic case. Baring minimal requirements the standard imposes, types can be any size the implementation wants to make them.
To go along with that, The compiler is not allowed to reorder class member to make it more efficient. The standard mandates that the objects must be laid out in their declared order (by access modifier), so that's out as well.
You can use fixed width types like
struct foo
int64_t a;
int16_t b;
int8_t c;
int8_t d;
;
and this will be the same on all platforms, provided they supply those types, but it only works with integer types. There are no fixed width floating point types and many standard objects/containers can be different sizes on different platforms.
Adding salt to the wound, floating point types are frequently hyper sensitive to bus-alignment positions, thereby enhancing the no-silver-bullet mantra. Regardless, this is very useful when loading up structs with anything other than floating point and potentially pointers. I use it frequently.
– WhozCraig
9 hours ago
Why isn’t member rearrangement allowed? Could you clarify?
– Yan B.
9 hours ago
2
If you take the cross-platform portability to the limit, note that these "exact width" types are optional. Every platform must haveint_least16_t
andint_fast16_t
, but (for example ifCHAR_BIT != 8
),int16_t
need not exist on a given platform.
– DevSolar
9 hours ago
@DevSolar While they are optional, the code will fail to compile if they are not present so at least you wont get binary that blows up on you.
– NathanOliver
9 hours ago
1
@YanB. It is mandated by the standard. see: eel.is/c++draft/class.mem#19
– NathanOliver
9 hours ago
|
show 1 more comment
You can use #pragma pack(1)
, but the very reason of this is that the compiler optimizes. Accessing a variable through the full register is faster than accessing it to the least bit.
Specific packing is only useful for serialization and intercompiler compatibility, etc.
As NathanOliver correctly added, this might even fail on some platforms.
3
May want to note this carries potential performance issues or may cause the code to not work on some platforms: stackoverflow.com/questions/7793511/…
– NathanOliver
9 hours ago
1
To my knowledge, using#pragma pack
causes potential performance issues and as such is not the desired solution.
– Yan B.
9 hours ago
add a comment |
Well, maybe I'm cooking the concept wrong, but you can use std::aligned_storage
to allocate your data. Applied to the struct, considered above, it could be something like that:
#include <type_traits>
#include <iostream>
#include <algorithm>
struct X
int a;
double b;
int c;
;
int main()
const std::size_t TOTAL_SIZE = sizeof(int) + sizeof(double) + sizeof(int);
// const std::size_t MAX_ALIGNMENT = std::max(alignof(double), alignof(int));
const std::size_t MAX_ALIGNMENT = alignof(X); //probably a better approach than above
std::aligned_storage<TOTAL_SIZE, MAX_ALIGNMENT>::type buffer;
X* pX = new(static_cast<void*>(&buffer)) X;
std::cout << "but sizeof(buffer) = " << sizeof(buffer) << std::endl;
pX->a = 10;
pX->b = 12334.5353;
pX->c = 44;
std::cout << pX->a << "t" << pX->b << "t" << pX->c << std::endl;
return 0;
There is no delete
, because placement-new handles the allocation, so that it happenes on stack (buffer
is a stack variable). Also, something more sophisticated should be passed as template parameters, some compile-time calculations of the desired buffer size and alignment (honestly, that's where I'm not quite sure of myself). ...and maybe you'll have to use types like int16_t
, and probably you'd better reorder members of the struct taking into account all the considerations, that have already been proposed about that.
But the primary idea is like that.
AFAIK, different tricks like "Small Object Optimization" are done that way, if you compiler supports the corresponding standard, that trick should save your efforrts. Standard library implementation's sources from GCC are full of similar things, just a lot more well-thought-out.
add a comment |
Your Answer
StackExchange.ifUsing("editor", function ()
StackExchange.using("externalEditor", function ()
StackExchange.using("snippets", function ()
StackExchange.snippets.init();
);
);
, "code-snippets");
StackExchange.ready(function()
var channelOptions =
tags: "".split(" "),
id: "1"
;
initTagRenderer("".split(" "), "".split(" "), channelOptions);
StackExchange.using("externalEditor", function()
// Have to fire editor after snippets, if snippets enabled
if (StackExchange.settings.snippets.snippetsEnabled)
StackExchange.using("snippets", function()
createEditor();
);
else
createEditor();
);
function createEditor()
StackExchange.prepareEditor(
heartbeatType: 'answer',
autoActivateHeartbeat: false,
convertImagesToLinks: true,
noModals: true,
showLowRepImageUploadWarning: true,
reputationToPostImages: 10,
bindNavPrevention: true,
postfix: "",
imageUploader:
brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
allowUrls: true
,
onDemand: true,
discardSelector: ".discard-answer"
,immediatelyShowMarkdownHelp:true
);
);
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
StackExchange.ready(
function ()
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f56761591%2fhow-to-organize-members-in-a-struct-to-waste-least-space-on-alignment%23new-answer', 'question_page');
);
Post as a guest
Required, but never shown
4 Answers
4
active
oldest
votes
4 Answers
4
active
oldest
votes
active
oldest
votes
active
oldest
votes
gcc has the -Wpadded
warning that warns when padding is added to a structure:
https://godbolt.org/z/iwO5Q3:
<source>:4:12: warning: padding struct to align 'X::b' [-Wpadded]
4 | double b;
| ^
<source>:1:8: warning: padding struct size to alignment boundary [-Wpadded]
1 | struct X
| ^
And you can manually rearrange members so that there is less / no padding. But this is not a cross platform solution, as different types can have different sizes / alignments on different system (Most notably pointers being 4 or 8 bytes on different architectures). The general rule of thumb is go from largest to smallest alignment when declaring members, and if you're still worried, compile your code with -Wpadded
once (But I wouldn't keep it on generally, because padding is necessary sometimes).
As for the reason why the compiler can't do it automatically is because of the standard ([class.mem]/19). It guarantees that, because this is a simple struct with only public members, &x.a < &x.c
(for some X x;
), so they can't be rearranged.
1
I honestly didn't think I'd see something useful come out of this question. Wasn't aware of that gcc option (and now I'm hopign clang has it as well). Thanks for teaching me something. tick.
– WhozCraig
9 hours ago
add a comment |
gcc has the -Wpadded
warning that warns when padding is added to a structure:
https://godbolt.org/z/iwO5Q3:
<source>:4:12: warning: padding struct to align 'X::b' [-Wpadded]
4 | double b;
| ^
<source>:1:8: warning: padding struct size to alignment boundary [-Wpadded]
1 | struct X
| ^
And you can manually rearrange members so that there is less / no padding. But this is not a cross platform solution, as different types can have different sizes / alignments on different system (Most notably pointers being 4 or 8 bytes on different architectures). The general rule of thumb is go from largest to smallest alignment when declaring members, and if you're still worried, compile your code with -Wpadded
once (But I wouldn't keep it on generally, because padding is necessary sometimes).
As for the reason why the compiler can't do it automatically is because of the standard ([class.mem]/19). It guarantees that, because this is a simple struct with only public members, &x.a < &x.c
(for some X x;
), so they can't be rearranged.
1
I honestly didn't think I'd see something useful come out of this question. Wasn't aware of that gcc option (and now I'm hopign clang has it as well). Thanks for teaching me something. tick.
– WhozCraig
9 hours ago
add a comment |
gcc has the -Wpadded
warning that warns when padding is added to a structure:
https://godbolt.org/z/iwO5Q3:
<source>:4:12: warning: padding struct to align 'X::b' [-Wpadded]
4 | double b;
| ^
<source>:1:8: warning: padding struct size to alignment boundary [-Wpadded]
1 | struct X
| ^
And you can manually rearrange members so that there is less / no padding. But this is not a cross platform solution, as different types can have different sizes / alignments on different system (Most notably pointers being 4 or 8 bytes on different architectures). The general rule of thumb is go from largest to smallest alignment when declaring members, and if you're still worried, compile your code with -Wpadded
once (But I wouldn't keep it on generally, because padding is necessary sometimes).
As for the reason why the compiler can't do it automatically is because of the standard ([class.mem]/19). It guarantees that, because this is a simple struct with only public members, &x.a < &x.c
(for some X x;
), so they can't be rearranged.
gcc has the -Wpadded
warning that warns when padding is added to a structure:
https://godbolt.org/z/iwO5Q3:
<source>:4:12: warning: padding struct to align 'X::b' [-Wpadded]
4 | double b;
| ^
<source>:1:8: warning: padding struct size to alignment boundary [-Wpadded]
1 | struct X
| ^
And you can manually rearrange members so that there is less / no padding. But this is not a cross platform solution, as different types can have different sizes / alignments on different system (Most notably pointers being 4 or 8 bytes on different architectures). The general rule of thumb is go from largest to smallest alignment when declaring members, and if you're still worried, compile your code with -Wpadded
once (But I wouldn't keep it on generally, because padding is necessary sometimes).
As for the reason why the compiler can't do it automatically is because of the standard ([class.mem]/19). It guarantees that, because this is a simple struct with only public members, &x.a < &x.c
(for some X x;
), so they can't be rearranged.
edited 9 hours ago
answered 9 hours ago
ArtyerArtyer
6,9199 silver badges31 bronze badges
6,9199 silver badges31 bronze badges
1
I honestly didn't think I'd see something useful come out of this question. Wasn't aware of that gcc option (and now I'm hopign clang has it as well). Thanks for teaching me something. tick.
– WhozCraig
9 hours ago
add a comment |
1
I honestly didn't think I'd see something useful come out of this question. Wasn't aware of that gcc option (and now I'm hopign clang has it as well). Thanks for teaching me something. tick.
– WhozCraig
9 hours ago
1
1
I honestly didn't think I'd see something useful come out of this question. Wasn't aware of that gcc option (and now I'm hopign clang has it as well). Thanks for teaching me something. tick.
– WhozCraig
9 hours ago
I honestly didn't think I'd see something useful come out of this question. Wasn't aware of that gcc option (and now I'm hopign clang has it as well). Thanks for teaching me something. tick.
– WhozCraig
9 hours ago
add a comment |
There really isn't a portable solution in the generic case. Baring minimal requirements the standard imposes, types can be any size the implementation wants to make them.
To go along with that, The compiler is not allowed to reorder class member to make it more efficient. The standard mandates that the objects must be laid out in their declared order (by access modifier), so that's out as well.
You can use fixed width types like
struct foo
int64_t a;
int16_t b;
int8_t c;
int8_t d;
;
and this will be the same on all platforms, provided they supply those types, but it only works with integer types. There are no fixed width floating point types and many standard objects/containers can be different sizes on different platforms.
Adding salt to the wound, floating point types are frequently hyper sensitive to bus-alignment positions, thereby enhancing the no-silver-bullet mantra. Regardless, this is very useful when loading up structs with anything other than floating point and potentially pointers. I use it frequently.
– WhozCraig
9 hours ago
Why isn’t member rearrangement allowed? Could you clarify?
– Yan B.
9 hours ago
2
If you take the cross-platform portability to the limit, note that these "exact width" types are optional. Every platform must haveint_least16_t
andint_fast16_t
, but (for example ifCHAR_BIT != 8
),int16_t
need not exist on a given platform.
– DevSolar
9 hours ago
@DevSolar While they are optional, the code will fail to compile if they are not present so at least you wont get binary that blows up on you.
– NathanOliver
9 hours ago
1
@YanB. It is mandated by the standard. see: eel.is/c++draft/class.mem#19
– NathanOliver
9 hours ago
|
show 1 more comment
There really isn't a portable solution in the generic case. Baring minimal requirements the standard imposes, types can be any size the implementation wants to make them.
To go along with that, The compiler is not allowed to reorder class member to make it more efficient. The standard mandates that the objects must be laid out in their declared order (by access modifier), so that's out as well.
You can use fixed width types like
struct foo
int64_t a;
int16_t b;
int8_t c;
int8_t d;
;
and this will be the same on all platforms, provided they supply those types, but it only works with integer types. There are no fixed width floating point types and many standard objects/containers can be different sizes on different platforms.
Adding salt to the wound, floating point types are frequently hyper sensitive to bus-alignment positions, thereby enhancing the no-silver-bullet mantra. Regardless, this is very useful when loading up structs with anything other than floating point and potentially pointers. I use it frequently.
– WhozCraig
9 hours ago
Why isn’t member rearrangement allowed? Could you clarify?
– Yan B.
9 hours ago
2
If you take the cross-platform portability to the limit, note that these "exact width" types are optional. Every platform must haveint_least16_t
andint_fast16_t
, but (for example ifCHAR_BIT != 8
),int16_t
need not exist on a given platform.
– DevSolar
9 hours ago
@DevSolar While they are optional, the code will fail to compile if they are not present so at least you wont get binary that blows up on you.
– NathanOliver
9 hours ago
1
@YanB. It is mandated by the standard. see: eel.is/c++draft/class.mem#19
– NathanOliver
9 hours ago
|
show 1 more comment
There really isn't a portable solution in the generic case. Baring minimal requirements the standard imposes, types can be any size the implementation wants to make them.
To go along with that, The compiler is not allowed to reorder class member to make it more efficient. The standard mandates that the objects must be laid out in their declared order (by access modifier), so that's out as well.
You can use fixed width types like
struct foo
int64_t a;
int16_t b;
int8_t c;
int8_t d;
;
and this will be the same on all platforms, provided they supply those types, but it only works with integer types. There are no fixed width floating point types and many standard objects/containers can be different sizes on different platforms.
There really isn't a portable solution in the generic case. Baring minimal requirements the standard imposes, types can be any size the implementation wants to make them.
To go along with that, The compiler is not allowed to reorder class member to make it more efficient. The standard mandates that the objects must be laid out in their declared order (by access modifier), so that's out as well.
You can use fixed width types like
struct foo
int64_t a;
int16_t b;
int8_t c;
int8_t d;
;
and this will be the same on all platforms, provided they supply those types, but it only works with integer types. There are no fixed width floating point types and many standard objects/containers can be different sizes on different platforms.
edited 9 hours ago
answered 9 hours ago
NathanOliverNathanOliver
106k19 gold badges159 silver badges235 bronze badges
106k19 gold badges159 silver badges235 bronze badges
Adding salt to the wound, floating point types are frequently hyper sensitive to bus-alignment positions, thereby enhancing the no-silver-bullet mantra. Regardless, this is very useful when loading up structs with anything other than floating point and potentially pointers. I use it frequently.
– WhozCraig
9 hours ago
Why isn’t member rearrangement allowed? Could you clarify?
– Yan B.
9 hours ago
2
If you take the cross-platform portability to the limit, note that these "exact width" types are optional. Every platform must haveint_least16_t
andint_fast16_t
, but (for example ifCHAR_BIT != 8
),int16_t
need not exist on a given platform.
– DevSolar
9 hours ago
@DevSolar While they are optional, the code will fail to compile if they are not present so at least you wont get binary that blows up on you.
– NathanOliver
9 hours ago
1
@YanB. It is mandated by the standard. see: eel.is/c++draft/class.mem#19
– NathanOliver
9 hours ago
|
show 1 more comment
Adding salt to the wound, floating point types are frequently hyper sensitive to bus-alignment positions, thereby enhancing the no-silver-bullet mantra. Regardless, this is very useful when loading up structs with anything other than floating point and potentially pointers. I use it frequently.
– WhozCraig
9 hours ago
Why isn’t member rearrangement allowed? Could you clarify?
– Yan B.
9 hours ago
2
If you take the cross-platform portability to the limit, note that these "exact width" types are optional. Every platform must haveint_least16_t
andint_fast16_t
, but (for example ifCHAR_BIT != 8
),int16_t
need not exist on a given platform.
– DevSolar
9 hours ago
@DevSolar While they are optional, the code will fail to compile if they are not present so at least you wont get binary that blows up on you.
– NathanOliver
9 hours ago
1
@YanB. It is mandated by the standard. see: eel.is/c++draft/class.mem#19
– NathanOliver
9 hours ago
Adding salt to the wound, floating point types are frequently hyper sensitive to bus-alignment positions, thereby enhancing the no-silver-bullet mantra. Regardless, this is very useful when loading up structs with anything other than floating point and potentially pointers. I use it frequently.
– WhozCraig
9 hours ago
Adding salt to the wound, floating point types are frequently hyper sensitive to bus-alignment positions, thereby enhancing the no-silver-bullet mantra. Regardless, this is very useful when loading up structs with anything other than floating point and potentially pointers. I use it frequently.
– WhozCraig
9 hours ago
Why isn’t member rearrangement allowed? Could you clarify?
– Yan B.
9 hours ago
Why isn’t member rearrangement allowed? Could you clarify?
– Yan B.
9 hours ago
2
2
If you take the cross-platform portability to the limit, note that these "exact width" types are optional. Every platform must have
int_least16_t
and int_fast16_t
, but (for example if CHAR_BIT != 8
), int16_t
need not exist on a given platform.– DevSolar
9 hours ago
If you take the cross-platform portability to the limit, note that these "exact width" types are optional. Every platform must have
int_least16_t
and int_fast16_t
, but (for example if CHAR_BIT != 8
), int16_t
need not exist on a given platform.– DevSolar
9 hours ago
@DevSolar While they are optional, the code will fail to compile if they are not present so at least you wont get binary that blows up on you.
– NathanOliver
9 hours ago
@DevSolar While they are optional, the code will fail to compile if they are not present so at least you wont get binary that blows up on you.
– NathanOliver
9 hours ago
1
1
@YanB. It is mandated by the standard. see: eel.is/c++draft/class.mem#19
– NathanOliver
9 hours ago
@YanB. It is mandated by the standard. see: eel.is/c++draft/class.mem#19
– NathanOliver
9 hours ago
|
show 1 more comment
You can use #pragma pack(1)
, but the very reason of this is that the compiler optimizes. Accessing a variable through the full register is faster than accessing it to the least bit.
Specific packing is only useful for serialization and intercompiler compatibility, etc.
As NathanOliver correctly added, this might even fail on some platforms.
3
May want to note this carries potential performance issues or may cause the code to not work on some platforms: stackoverflow.com/questions/7793511/…
– NathanOliver
9 hours ago
1
To my knowledge, using#pragma pack
causes potential performance issues and as such is not the desired solution.
– Yan B.
9 hours ago
add a comment |
You can use #pragma pack(1)
, but the very reason of this is that the compiler optimizes. Accessing a variable through the full register is faster than accessing it to the least bit.
Specific packing is only useful for serialization and intercompiler compatibility, etc.
As NathanOliver correctly added, this might even fail on some platforms.
3
May want to note this carries potential performance issues or may cause the code to not work on some platforms: stackoverflow.com/questions/7793511/…
– NathanOliver
9 hours ago
1
To my knowledge, using#pragma pack
causes potential performance issues and as such is not the desired solution.
– Yan B.
9 hours ago
add a comment |
You can use #pragma pack(1)
, but the very reason of this is that the compiler optimizes. Accessing a variable through the full register is faster than accessing it to the least bit.
Specific packing is only useful for serialization and intercompiler compatibility, etc.
As NathanOliver correctly added, this might even fail on some platforms.
You can use #pragma pack(1)
, but the very reason of this is that the compiler optimizes. Accessing a variable through the full register is faster than accessing it to the least bit.
Specific packing is only useful for serialization and intercompiler compatibility, etc.
As NathanOliver correctly added, this might even fail on some platforms.
edited 9 hours ago
answered 9 hours ago
Michael ChourdakisMichael Chourdakis
3,9761 gold badge20 silver badges44 bronze badges
3,9761 gold badge20 silver badges44 bronze badges
3
May want to note this carries potential performance issues or may cause the code to not work on some platforms: stackoverflow.com/questions/7793511/…
– NathanOliver
9 hours ago
1
To my knowledge, using#pragma pack
causes potential performance issues and as such is not the desired solution.
– Yan B.
9 hours ago
add a comment |
3
May want to note this carries potential performance issues or may cause the code to not work on some platforms: stackoverflow.com/questions/7793511/…
– NathanOliver
9 hours ago
1
To my knowledge, using#pragma pack
causes potential performance issues and as such is not the desired solution.
– Yan B.
9 hours ago
3
3
May want to note this carries potential performance issues or may cause the code to not work on some platforms: stackoverflow.com/questions/7793511/…
– NathanOliver
9 hours ago
May want to note this carries potential performance issues or may cause the code to not work on some platforms: stackoverflow.com/questions/7793511/…
– NathanOliver
9 hours ago
1
1
To my knowledge, using
#pragma pack
causes potential performance issues and as such is not the desired solution.– Yan B.
9 hours ago
To my knowledge, using
#pragma pack
causes potential performance issues and as such is not the desired solution.– Yan B.
9 hours ago
add a comment |
Well, maybe I'm cooking the concept wrong, but you can use std::aligned_storage
to allocate your data. Applied to the struct, considered above, it could be something like that:
#include <type_traits>
#include <iostream>
#include <algorithm>
struct X
int a;
double b;
int c;
;
int main()
const std::size_t TOTAL_SIZE = sizeof(int) + sizeof(double) + sizeof(int);
// const std::size_t MAX_ALIGNMENT = std::max(alignof(double), alignof(int));
const std::size_t MAX_ALIGNMENT = alignof(X); //probably a better approach than above
std::aligned_storage<TOTAL_SIZE, MAX_ALIGNMENT>::type buffer;
X* pX = new(static_cast<void*>(&buffer)) X;
std::cout << "but sizeof(buffer) = " << sizeof(buffer) << std::endl;
pX->a = 10;
pX->b = 12334.5353;
pX->c = 44;
std::cout << pX->a << "t" << pX->b << "t" << pX->c << std::endl;
return 0;
There is no delete
, because placement-new handles the allocation, so that it happenes on stack (buffer
is a stack variable). Also, something more sophisticated should be passed as template parameters, some compile-time calculations of the desired buffer size and alignment (honestly, that's where I'm not quite sure of myself). ...and maybe you'll have to use types like int16_t
, and probably you'd better reorder members of the struct taking into account all the considerations, that have already been proposed about that.
But the primary idea is like that.
AFAIK, different tricks like "Small Object Optimization" are done that way, if you compiler supports the corresponding standard, that trick should save your efforrts. Standard library implementation's sources from GCC are full of similar things, just a lot more well-thought-out.
add a comment |
Well, maybe I'm cooking the concept wrong, but you can use std::aligned_storage
to allocate your data. Applied to the struct, considered above, it could be something like that:
#include <type_traits>
#include <iostream>
#include <algorithm>
struct X
int a;
double b;
int c;
;
int main()
const std::size_t TOTAL_SIZE = sizeof(int) + sizeof(double) + sizeof(int);
// const std::size_t MAX_ALIGNMENT = std::max(alignof(double), alignof(int));
const std::size_t MAX_ALIGNMENT = alignof(X); //probably a better approach than above
std::aligned_storage<TOTAL_SIZE, MAX_ALIGNMENT>::type buffer;
X* pX = new(static_cast<void*>(&buffer)) X;
std::cout << "but sizeof(buffer) = " << sizeof(buffer) << std::endl;
pX->a = 10;
pX->b = 12334.5353;
pX->c = 44;
std::cout << pX->a << "t" << pX->b << "t" << pX->c << std::endl;
return 0;
There is no delete
, because placement-new handles the allocation, so that it happenes on stack (buffer
is a stack variable). Also, something more sophisticated should be passed as template parameters, some compile-time calculations of the desired buffer size and alignment (honestly, that's where I'm not quite sure of myself). ...and maybe you'll have to use types like int16_t
, and probably you'd better reorder members of the struct taking into account all the considerations, that have already been proposed about that.
But the primary idea is like that.
AFAIK, different tricks like "Small Object Optimization" are done that way, if you compiler supports the corresponding standard, that trick should save your efforrts. Standard library implementation's sources from GCC are full of similar things, just a lot more well-thought-out.
add a comment |
Well, maybe I'm cooking the concept wrong, but you can use std::aligned_storage
to allocate your data. Applied to the struct, considered above, it could be something like that:
#include <type_traits>
#include <iostream>
#include <algorithm>
struct X
int a;
double b;
int c;
;
int main()
const std::size_t TOTAL_SIZE = sizeof(int) + sizeof(double) + sizeof(int);
// const std::size_t MAX_ALIGNMENT = std::max(alignof(double), alignof(int));
const std::size_t MAX_ALIGNMENT = alignof(X); //probably a better approach than above
std::aligned_storage<TOTAL_SIZE, MAX_ALIGNMENT>::type buffer;
X* pX = new(static_cast<void*>(&buffer)) X;
std::cout << "but sizeof(buffer) = " << sizeof(buffer) << std::endl;
pX->a = 10;
pX->b = 12334.5353;
pX->c = 44;
std::cout << pX->a << "t" << pX->b << "t" << pX->c << std::endl;
return 0;
There is no delete
, because placement-new handles the allocation, so that it happenes on stack (buffer
is a stack variable). Also, something more sophisticated should be passed as template parameters, some compile-time calculations of the desired buffer size and alignment (honestly, that's where I'm not quite sure of myself). ...and maybe you'll have to use types like int16_t
, and probably you'd better reorder members of the struct taking into account all the considerations, that have already been proposed about that.
But the primary idea is like that.
AFAIK, different tricks like "Small Object Optimization" are done that way, if you compiler supports the corresponding standard, that trick should save your efforrts. Standard library implementation's sources from GCC are full of similar things, just a lot more well-thought-out.
Well, maybe I'm cooking the concept wrong, but you can use std::aligned_storage
to allocate your data. Applied to the struct, considered above, it could be something like that:
#include <type_traits>
#include <iostream>
#include <algorithm>
struct X
int a;
double b;
int c;
;
int main()
const std::size_t TOTAL_SIZE = sizeof(int) + sizeof(double) + sizeof(int);
// const std::size_t MAX_ALIGNMENT = std::max(alignof(double), alignof(int));
const std::size_t MAX_ALIGNMENT = alignof(X); //probably a better approach than above
std::aligned_storage<TOTAL_SIZE, MAX_ALIGNMENT>::type buffer;
X* pX = new(static_cast<void*>(&buffer)) X;
std::cout << "but sizeof(buffer) = " << sizeof(buffer) << std::endl;
pX->a = 10;
pX->b = 12334.5353;
pX->c = 44;
std::cout << pX->a << "t" << pX->b << "t" << pX->c << std::endl;
return 0;
There is no delete
, because placement-new handles the allocation, so that it happenes on stack (buffer
is a stack variable). Also, something more sophisticated should be passed as template parameters, some compile-time calculations of the desired buffer size and alignment (honestly, that's where I'm not quite sure of myself). ...and maybe you'll have to use types like int16_t
, and probably you'd better reorder members of the struct taking into account all the considerations, that have already been proposed about that.
But the primary idea is like that.
AFAIK, different tricks like "Small Object Optimization" are done that way, if you compiler supports the corresponding standard, that trick should save your efforrts. Standard library implementation's sources from GCC are full of similar things, just a lot more well-thought-out.
edited 7 hours ago
answered 8 hours ago
MasterAlerMasterAler
68711 silver badges20 bronze badges
68711 silver badges20 bronze badges
add a comment |
add a comment |
Thanks for contributing an answer to Stack Overflow!
- Please be sure to answer the question. Provide details and share your research!
But avoid …
- Asking for help, clarification, or responding to other answers.
- Making statements based on opinion; back them up with references or personal experience.
To learn more, see our tips on writing great answers.
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
StackExchange.ready(
function ()
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f56761591%2fhow-to-organize-members-in-a-struct-to-waste-least-space-on-alignment%23new-answer', 'question_page');
);
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
If you need "arrays" of hundreds of millions of elements, then perhaps arrays is not the correct data-structure to begin with? At least not in-memory arrays (think memory mapped files, or perhaps even some kind of database)?
– Some programmer dude
9 hours ago
And really, the only possible answer to the question "[i]s there a reliable cross-platform way to solve this problem (minimize the amount of needed padding without suffering from decreased performance caused by misalignment)?" could only be a simple "no". There are probably compiler and system specific ways to work around it, but nothing truly portable or compiler/platform/system agnostic.
– Some programmer dude
9 hours ago
1
May be some portability benefits from using fixed width integers so they don't change size on you.
– user4581301
9 hours ago
3
largest alignment requirements first. If none, then largest members first. Regarding your real question, yes there is a cross-compatible method for doing this: it's called a string. Outside of that, types using specified bit widths can help significantly, but still require endian handling if you're really serious about cross platform. In short, protocols exist specifically to address such issues and bridge the hard differences between platforms. Things like this are one of many reasons why they exist, Caveat: Good chance I completely misunderstood the "this" of this question.
– WhozCraig
9 hours ago
1
For all the reasons above, there is no one thing that guarantees a minimum storage for struct size, but @WhozCraig provides a precise explanation of the oversimplified rule Biggest First, Smallest Last in decreasing order of storage size required. That's about as reasonable an approach likely to minimize storage across compilers and hardware, but there is no guarantee any two structs will be allocated the same amount of storage between compilers (other than trivial examples (such as
struct foo int a, b; ;
)– David C. Rankin
8 hours ago