C++ Weekly - Ep 410 - What Are Padding and Alignment? (And Why You Might Care)

  Рет қаралды 15,552

C++ Weekly With Jason Turner

C++ Weekly With Jason Turner

Күн бұрын

Пікірлер: 89
@kuhluhOG
@kuhluhOG 9 ай бұрын
One tip when rearranging data members to avoid padding: Put your biggest members FIRST.
@Minty_Meeo
@Minty_Meeo 9 ай бұрын
Dude Jason was driving me nuts in this episode by doing the complete opposite of this!
@hampus23
@hampus23 2 күн бұрын
Exactly
@victotronics
@victotronics 9 ай бұрын
Next episode: what are cachelines and why do want to align for them?
@alexvergara2491
@alexvergara2491 9 ай бұрын
BEST comment and idea
@dmitriidemenev5258
@dmitriidemenev5258 9 ай бұрын
2nd next episode: what is endianness or byte order. Also, the monstrosity of the past - mixed-endianness.
@stephenhowe4107
@stephenhowe4107 9 ай бұрын
1. I generally arrange largest to smallest members in a struct. That means that 1-byte padding after the i would not occur. 2. But there is other padding as well. There is often padding at the end of the struct. This is so, if you have an array of this struct, the next item will start on the proper boundary.
@stephenhowe4107
@stephenhowe4107 9 ай бұрын
By largest to smallest members, I mean by type. So largest type first, smallest type last.
@Christosg8
@Christosg8 9 ай бұрын
This was a nice opportunity to talk about bitfields as well and how the behave under alignment. We use them a lot at work (these 1-bit bitfields are a pain) and I've been bitten before due to alignment requirements of bitfields...
@Tyranisaur
@Tyranisaur 9 ай бұрын
I think I'm using packed structs correctly, by not using it 😃
@ABaumstumpf
@ABaumstumpf 9 ай бұрын
Same thing here :)
@bernardmayeur3952
@bernardmayeur3952 9 ай бұрын
@Jason, why not start with the biggest type first? By starting with the biggest you always have the most optimal struct size right? 8+4+4+1+1+1 (+1 for alignment here) = 20 or 24
@bernardmayeur3952
@bernardmayeur3952 9 ай бұрын
Never mind. Yours will also work. I was thinking that packing biggest first was a best practice for cache. Seems both way works
@HinaraT
@HinaraT 9 ай бұрын
Yes but your solution prevent the padded warning for clang on the fields and instead put it on the struct
@snbv5real
@snbv5real 9 ай бұрын
I don't usually use packed structs... *if I'm in control of the struct definition*. I usually manually pack the struct and static_assert() the size is what I manually calculated, this comes up a *lot* in Vulkan/OpenGL/ anything that touches GLSL, where default alignment rules are not like C++, and default to *large* padding amounts. In the case of OpenGL/Vulkan code, I will often actually manually insert padding variables because those rules don't line up with C++. For a lot of other uses, in particular *data serialization*, I'm forced to pack structures, because the structures are *defined* to be packed. There's a data format I have to use a lot, that *must be packed* when over the wire or stored via io, otherwise none of the functions de-serializing it will work. It's sad, because the structure *could* have been re-arranged such that packing was unnecessary, though the order of elements may not have been as human friendly.
@danielkatzav9971
@danielkatzav9971 9 ай бұрын
Hey Jason ! I was actually waiting for a good video from you about this matter I do use packed struct - but as part of multiple embedded environments. I would be happy share my thoughts and takes and learn from that experience.
@not_ever
@not_ever 9 ай бұрын
Clang tidy will also detect padding issues if you can’t use Wpadded. Apologies if this was said I’m in a noisy environment
@avramlevitter6150
@avramlevitter6150 9 ай бұрын
This may seem like a minor issue, and it could be in a lot of projects (how many instances are you going to have of this particular struct?) but in some applications you might have millions of these you need to allocate and iterate, and in those the order of the fields is absolutely critical. And saving space isn't always better- due to the way memory access works, you might want to put members that are accessed together frequently next to each other even though it means the compiler injects a lot of padding.
@caiovinicius7970
@caiovinicius7970 5 ай бұрын
to avoid padded warnings you can introduce "char padding" members in your struct, to fill the gaps. this also allow for more easy knowing of were you can put new members in this struct wo breaking the alignment
@Omnifarious0
@Omnifarious0 9 ай бұрын
I've always put the smallest ones at the end. I'm not sure which is better in general. If you have them in an array of course, the struct has to be padded out to the correct alignment for the most constrained element in it to be on the right boundary, and so I think that negates any advantage for ascending vs. descending size order.
@Денис-ь8ь7с
@Денис-ь8ь7с 4 ай бұрын
I believe that when you arrange in largest-to-smallest way, you always get the best result. Because every smaller-to-larger pair causes padding and larger-to-smaller (or same-to-same) not. And end-of-the-struct padding with proper ordering consequently will be at least not bigger than total padding for any other member permutation case.
@LeDabe
@LeDabe 9 ай бұрын
A quick fix is simply to start the struct with the largest type and continue with the smallest type. If we assume every type is a power of two in size, you can prove that you will have the less padding this way.
@LeDabe
@LeDabe 9 ай бұрын
so does sorting the values from smallest to largest AFAIK
@WndSks
@WndSks 9 ай бұрын
X86 can access the first x bytes in the struct faster than later bytes, also sort by how important the member is. (I don't remember what x is, 256 perhaps)
@MirralisDias
@MirralisDias 9 ай бұрын
​@@LeDabeI was expecting him to place the long long first, then the ints, and then the chars. I can't test it now, but in this way would it be possible to get 19 bytes?
@loicballeydier5546
@loicballeydier5546 9 ай бұрын
@@MirralisDias i think you have to be aligned on 8 bytes (64bit OS) so it will be also 24 bytes
@AlfredoCorrea
@AlfredoCorrea 9 ай бұрын
it seems to me that the general rule is that you can do small to large or large to small or any “std::rotate” :) of that. no?
@FWindowsUseGaruda
@FWindowsUseGaruda 9 ай бұрын
Thank you, this was an excellent explanation.
@anon_y_mousse
@anon_y_mousse 8 ай бұрын
Your manipulation of tabular data had me wondering if CE could do blockwise selections, since it has a limited subset of Vim keybindings, and apparently it can. So, just a tiny tip for you for next time you want to demonstrate editing a table of data, such as comments at the end of every line, you can just hit ctrl+v and select the entire block at once then x or d to delete it. You just need to enable Vim keybindings in the interface.
@PGJVids
@PGJVids 9 ай бұрын
Arranging the values from largest size to smallest size, then no padding would ever be used between values (64bit at the top, followed by 32bit, then 16bit, then 8bit). There could still be padding at the end when you have the structs in an array, to make sure the alignment of the next struct is correct. All this about alignment and padding is something i've had to deal with a bit while learning to use the Vulkan API, since the GPU doesn't handle it for you at all.
@badassopenpolling
@badassopenpolling 9 ай бұрын
Add data memebers in descending order of their size- then you will get optimal padding
@nicholaskomsa1777
@nicholaskomsa1777 5 ай бұрын
padding issues are solved largely by Structures of Arrays programming method, speed increase even more dramatic than worrying about complicated structure concepts.
@tigrankato
@tigrankato 9 ай бұрын
Is there any way to tell the compiler to automatically reorder struct members for the smallest possible size?
@ZHDINC
@ZHDINC 9 ай бұрын
I'm curious about this as well. It seems like it'd be something trivial for the compiler to optimize. I mean, I certainly don't care if the compiler re-arranged the ordering of class members so they'll use less space.
@imtootired4122
@imtootired4122 9 ай бұрын
C++23 requires that the order of the members in memory to match the order in the definition. Earlier standards were a bit looser and allowed members with different access control to be re-ordered.
@cppweekly
@cppweekly 9 ай бұрын
@@imtootired4122 But no one did
@nicholaskomsa1777
@nicholaskomsa1777 5 ай бұрын
first of all, I'd more than likely be using items like std::uint16_t or std::uint32_t, and then std::size_t. Your code appears depreciated.
@cppweekly
@cppweekly 5 ай бұрын
Not at all - size_t means "native machine size type" this is the correct thing to do for crossplatform code. int32, etc, should be used when I want to specify the exact type right now.
@nicholaskomsa1777
@nicholaskomsa1777 5 ай бұрын
@@cppweekly Rather than using c-style data types that aren't quite so clear about their properties, which you describe in your video. Instead, if you want to clarify them - which is always - you use std data types and constructs. std::size_t is not designed to be portable, it's supposed to be the largest possible unsigned integer-type the system supports. std::size_t is entirely system dependent by design.
@mytech6779
@mytech6779 9 ай бұрын
Most of the time address 0x00 is special and not used for normal allocation, thus it is overloaded as the null pointer address. There are exceptions though where derefrencing a pointer to 0x00 is a valid thing to do and not the same as trying to deref a null pointer. Really a lot of systems avoid the whole thing with special handling of 0x00 page in the virtual address mapping. (boilerplate disclaimer: If either special alignment or access to 0x00 really matters then double check the manuals for your system; hardware and OS) Though I can see how 0x00 being considered special could lead to assumptions that create an off by one alignment error.
@LesleyLai
@LesleyLai 9 ай бұрын
Anyone has an idea about why do you ever want to use std::alignment_of and use std::aligned_storage instead of alignof and alignas?
@friedkeenan
@friedkeenan 9 ай бұрын
You don't want to use them, as I understand it. std::alignment_of was created before `alignof` existed, but now `alignof` supersedes it in all ways, though it still works fine. std::aligned_storage in fact can't alias for other objects like an alignas(T) std::byte[sizeof(T)] could, so using std::aligned_storage is probably in fact an error
@bryce.ferenczi
@bryce.ferenczi 9 ай бұрын
You probabbly wouldn't want to use std::aligned_storage in greenfield code now since its depricated in cpp23+
@bryce.ferenczi
@bryce.ferenczi 9 ай бұрын
You probabbly wouldn't want to use std::aligned_storage in greenfield code now since its depricated in cpp23+
@friedkeenan
@friedkeenan 9 ай бұрын
Not only can unaligned access be slower, but it can also be simply disallowed by the hardware and cause a crash.
@Minty_Meeo
@Minty_Meeo 9 ай бұрын
PowerPC had really great support for unaligned writes... except for the Wii which shipped with a hardware bug that corrupts unaligned writes to uncached memory! It's usually not worth the risk to invoke the terror of unaligned writes on any platform.
@schmide
@schmide 9 ай бұрын
Must is not correct. x86 is a byte addressable machine. There is no alignment restrictions on basic types. (char, short, int, float, double, long long). If they do cross their alignment, there is at most a load delay if the cpu crosses a cache line boundary. (64 bytes) In previous generations (sandy bridge and before) vector instructions (SSE/AVX) would fault if they were not aligned to a 128bit boundary, this has been relaxed since then and they will not fault as long as they are aligned to a dword. Regardless of all this it is good practice to align data. It matters on older hardware and ARM/RISC/GPU can often require greater alignment. As for what the user has to consider. For modern OSs, all heap allocations are cache aligned at 64bytes, stack primitives are often aligned as well, so if you are doing vector processing you need not declare alignment as you did before. As for manual ordering, it is best and easiest to put the largest types first, then the rest will fall into place. If you put smaller primitives first you have to group them to align with the latter elements or padding will be introduced.
@lysy-zn2gg
@lysy-zn2gg 9 ай бұрын
I think you should only care in critical parts of code like Vertex structs in game development etc
@seanmacfoy5326
@seanmacfoy5326 9 ай бұрын
Does the last char not start on byte 24?
@pandacongolais
@pandacongolais 9 ай бұрын
The additional episodes list grows fast in the other comment. If not already done, please add _packing_ (+ endianess) I'm using this a lot in an embedded context. But I'm sure I'm missing some concepts, and you are certainly one of the most skilled to teach us !
@cppweekly
@cppweekly 9 ай бұрын
It is, in fact, impossible to keep track of the topic requests in the video comments! I have a tracker here where you can add your request so it won't get lost - github.com/lefticus/cpp_weekly/issues/
@pandacongolais
@pandacongolais 9 ай бұрын
@@cppweekly Done Maybe you should give this link in every video you publish, in the description or a pined comment. Anyway, a lot of thanks for your time and for making us less dumb !
@roblauer7568
@roblauer7568 9 ай бұрын
I might be wrong, but ~5:54 in line 20 the comment says that the char is in byte 25. Isn't it 24? char a; // [0, 1) (1) // padding // [1, 4) (3) int i; // [4, 8) (4) char b; // [8, 9) (1) // padding // [9, 12) (3) int j; // [12, 16) (4) long long l; // [16, 24) (8) char c; // [24, 25) (1)
@cppweekly
@cppweekly 9 ай бұрын
I probably did get something wrong, yeah.
@roblauer7568
@roblauer7568 9 ай бұрын
@@cppweekly thanks for your reply. I’m shocked that you take the time :O Thank you for all the great videos! I learn so much from them.
@njagimwaniki4321
@njagimwaniki4321 4 ай бұрын
@@roblauer7568 Why is the total byte usage here 32 and not 25? Is it because we have to store things in multiples of 8?
@ysakhno
@ysakhno 9 ай бұрын
You should have reversed the order of your fields in fact. As a rule of thumb, first should go all the long longs, then all ints, then all short ints (if you have them), then all chars/bytes/bools (if the size of bool is 1 byte). That is if you care about total size of your structs / performance so much. But in most cases this is largely irrelevant, in other words you should only care when you start to see problems.
@onaecO
@onaecO 9 ай бұрын
Any sources to really understand the deep stuff? Why this alignment gives optimization?
@宋哲宇-p2n
@宋哲宇-p2n 9 ай бұрын
I'm just curious about if the compiler can do the rearrangement for us automatically, since it's a seemingly simple optimization
@cppweekly
@cppweekly 9 ай бұрын
Absolutely not, because it would break ABI compatibility
@alpergunes6380
@alpergunes6380 9 ай бұрын
I usually prefer to add explicit padding to the end of my structs to make the wasted space explicit and visible. struct S { char c; char _pad[3]; int i; long long l; };
@AlfredoCorrea
@AlfredoCorrea 9 ай бұрын
this is ok, but not if you care about aggregate initialization. perhaps named field initialization is a workaround now, I haven’t tried.
@alpergunes6380
@alpergunes6380 9 ай бұрын
@@AlfredoCorrea true
@AlfredoCorrea
@AlfredoCorrea 9 ай бұрын
@@alpergunes6380 Perhaps a hypothetical "hidden" attribute could solve this. `hidden: char _pad[3];`
@milasudril
@milasudril 9 ай бұрын
Isn't packed structs for interfacing with odd-sized binary formats? The question is then if you should save values to an unpacked version of the same struct when loading data, or keep it as is despite a potentially slower access to individual fields.
@AtomicAndi
@AtomicAndi 9 ай бұрын
visual studio has a new feature to visualize class layout apparently I'm not allowed to post links
@AtomicAndi
@AtomicAndi 9 ай бұрын
oh, we are sponsored by CLion ;-)
@Minty_Meeo
@Minty_Meeo 9 ай бұрын
KZbin will block any comments with links to outside websites without exception. I'm not even sure if links to other KZbin videos always make it through the filter.
@AtomicAndi
@AtomicAndi 9 ай бұрын
@@Minty_Meeo I often comment with links to videos, so that's fine
@dmitriidemenev5258
@dmitriidemenev5258 9 ай бұрын
1:49 It's important to note that alignment of types is architecture dependent. 7:03 Such behavior was inherited from C and isn't that great because the order of fields that is useful for humans isn't particularly good for the compiler. I find that the Rust's behavior is better because there the order of fields in the binary representation is decided by the compiler unless the programmer opts into doing this manually. There is also a very important overlooked topic - trailing padding with nested structs. It can highlight the importance of compile-time reflection and maybe you can demonstrate a workaround with boost/pfr.
@mateuslima5102
@mateuslima5102 9 ай бұрын
i use packed structs to send data via serial protocol, is that correct?
@cppweekly
@cppweekly 9 ай бұрын
You've probably got undefined behavior on the other end, if you're using reinterpret_cast or a c-style cast.
@Yupppi
@Yupppi 9 ай бұрын
Why doesn't compiler do anything about the padding? I would've intuitively set long long first, then ints and then chars.
@rafi1082
@rafi1082 9 ай бұрын
wrapping the struct with "#pragma pack(1)" will make it compile
@charlesolson9019
@charlesolson9019 9 ай бұрын
That's a compiler-specific pragma, and I'm guessing it makes the code less efficient. I have done that in network protocol work, where you `reinterpret_cast()` a blob of data into a struct.
@bcodetube
@bcodetube 9 ай бұрын
#pragma pack(push, 1) struct X {×××} ; #pragma pack(pop) This is also useful to read binary files that have well defined headers
@mgeding
@mgeding 9 ай бұрын
Absolutely bizarre that there was no mention of the `ailgnof` operator.
@jasoncole7711
@jasoncole7711 9 ай бұрын
Historically I've also sorted stack variables to be largest to smallest size; I don't know whether the compiler is smart enough to rearrange them if declared less than optimally.
@cppweekly
@cppweekly 9 ай бұрын
On a modern compiler your stack objects are probably just residing in registers anyhow, or eliminated entirely. Your stack variables should be ordered in the way it logically makes sense to use and initialize them, and they should be limited in scope as much as possible usually.
@emilkaczmarek4641
@emilkaczmarek4641 9 ай бұрын
GCC 13.2 supports -Wpadded (cannot try earlier versions at the moment), but as warnings and is not as informative as clang.
@paulfee9839
@paulfee9839 9 ай бұрын
Testing with compiler explorer, GCC supports -Wpadded at least back to version 4.1.2.
@ChristophePiault
@ChristophePiault 9 ай бұрын
@@paulfee9839 It means that GCC supported -Wpadded before clang initial release. Pure free useless GCC bashing at 7:18.
@stephenhowe4107
@stephenhowe4107 9 ай бұрын
I use packed structs but only for structs that are written to disk. If they are not, I use the default packing. Usually this is achieved via #pragma pack.
@oracleoftroy
@oracleoftroy 8 ай бұрын
I would recommend not doing that. It is ok if you know your compiler, your platform, your cpu and don't need any sort of portability (the same computer will read and write the file) and are certain you won't run into alignment, packing or other issues no matter what happens in the future. Otherwise, I'd manually read/write the bytes in the proper order with the proper packing for the file. Something like: // write 32-bit little endian buf[0] = (value >> 0) && 0xFF; buf[1] = (value >> 8) && 0xFF; buf[2] = (value >> 16) && 0xFF; buf[3] = (value >> 24) && 0xFF; // read 32-bit little endian value = (buf[0]
@jeanclaudevanslamme
@jeanclaudevanslamme 9 ай бұрын
Are you seriously suggesting that I, someone who is watching C++ educational content, might be making mistakes in C++? >:(
@oldlonecoder5843
@oldlonecoder5843 9 ай бұрын
Wtf? Pack will address exact struct representation of physical memory address for devices and physical address of IO ports, registers, flags....!! Nothing to do with c++!!!!!!!! Wtf? Pack is to get out of c++ normal addressing data in memory (natural integer and address boundaries padding)
C++ Weekly - Ep 411 - Intro to C++ Exceptions
9:06
C++ Weekly With Jason Turner
Рет қаралды 10 М.
C++ Weekly - Ep 406 - Why Avoid Pointer Arithmetic?
10:22
C++ Weekly With Jason Turner
Рет қаралды 14 М.
Ouch.. 🤕⚽️
00:25
Celine Dept
Рет қаралды 27 МЛН
How it feels when u walk through first class
00:52
Adam W
Рет қаралды 26 МЛН
C++ Weekly - Ep 421 - You're Using optional, variant, pair, tuple, any, and expected Wrong!
10:34
C++ Weekly - Ep 435 - Easy GPU Programming With AdaptiveCpp (68x Faster!)
15:30
C++ Weekly With Jason Turner
Рет қаралды 15 М.
C++ Weekly - Ep 343 - Digging Into Type Erasure
15:16
C++ Weekly With Jason Turner
Рет қаралды 19 М.
Constructors Are Broken
18:16
Logan Smith
Рет қаралды 109 М.
C++ Weekly - Ep 404 - How (and Why) To Write Code That Avoids std::move
8:50
C++ Weekly With Jason Turner
Рет қаралды 31 М.
What I do to never have to worry about memory leaks!
8:03
Low Level Game Dev
Рет қаралды 38 М.
C++ Weekly - Ep 312 - Stop Using `constexpr` (And Use This Instead!)
18:24
C++ Weekly With Jason Turner
Рет қаралды 52 М.
I made a Compiler in 25 Days - Here is what I learned
40:59
Alex The Dev
Рет қаралды 60 М.
Why i think C++ is better than rust
32:48
ThePrimeTime
Рет қаралды 319 М.
C++ Weekly - Ep 400 - C++ is 40... Is C++ DYING?
20:51
C++ Weekly With Jason Turner
Рет қаралды 30 М.