Live data from Hacker News

The Lost Art of Structure Packing (2018)

catb.org

11–20 of 120 posts

Re: The Lost Art of Structure Packing (2018)

#11
post #5
post #2

It would be nice if there was an annotation that just lets the compiler do all the optimization for me for the cases where I don't care about the memory layout of the struct. Just like the Rust compiler can do without repr(C)

Wait, forgive my ignorance, isn’t this the default? If you don’t care about the memory layout then won’t the compiler reorg / pad structure members to fulfill alignment?

Nope, C and C++ compilers are not allowed to reorder struct fields (AFAIK at least, I haven't seen this yet in any real world compiler), but they will add padding bytes for natural alignment (and that's where the "waste" is coming from).

IMHO there are just as many arguments for automatic reordering as there are against it (e.g. creating structs that are layed over memory mapped IO registers, or just optimizing a struct for certain cache-efficient access patterns). In my opinion it's sufficient to know about the existance of alignment-padding, and how to work around it if needed (for instance reordering the struct members manually, or using #pragma pack)

Re: The Lost Art of Structure Packing (2018)

#12
post #5
post #2

It would be nice if there was an annotation that just lets the compiler do all the optimization for me for the cases where I don't care about the memory layout of the struct. Just like the Rust compiler can do without repr(C)

Wait, forgive my ignorance, isn’t this the default? If you don’t care about the memory layout then won’t the compiler reorg / pad structure members to fulfill alignment?

I see, thanks all.

Re: The Lost Art of Structure Packing (2018)

#13
post #4

Earlier quoted context omitted.

I have done some win32 programming but haven't encountered struct packing or alignment being an issue, where does that pop up?

I work in video games, and very recently we had a sneaky bug in one of our AAA titles(that was already out!), where(in huge simplification) we had a struct that looked like: struct Obj { int foo; bool bar; } then we were storing those in a custom hashmap using these as keys, where the hashing function was basically hashing bits of each stored object, without any awareness of what's in the object. The bug was found wh…

It's not just the different "under the hood size" that's a problem in this situation, but alignment-padding bytes added by the compiler inbetween struct members will have random junk data in them, the compiler will not zero-initialize padding bytes, unless you explicitely memset() the struct (and even then I wouldn't count on that the padding bytes aren't "tainted" later).

E.g. if you initialize a C struct or C++ object the "usual way":

Obj obj = { };

There will most definitely be junk in the padding bytes.

Re: The Lost Art of Structure Packing (2018)

#14
post #4

Earlier quoted context omitted.

I have done some win32 programming but haven't encountered struct packing or alignment being an issue, where does that pop up?

I work in video games, and very recently we had a sneaky bug in one of our AAA titles(that was already out!), where(in huge simplification) we had a struct that looked like: struct Obj { int foo; bool bar; } then we were storing those in a custom hashmap using these as keys, where the hashing function was basically hashing bits of each stored object, without any awareness of what's in the object. The bug was found wh…

In my first job, there was an interesting bug introduced by an un-terminated pragma-pack in a header file.

Because not every structure was packed, depending on your include order, some structures would be packed differently in different compilation units.

Except, for the only structures this happened for, the packed packing was coincidentally the same as the default packing ... when the program was compiled 32-bits. Attempting to switch from a 32-bit executable to a 64-bit executable resulted in mysterious segfaults as different compilation units disagreed on where different fields were.

Fun times!

Re: The Lost Art of Structure Packing (2018)

#15

Earlier quoted context omitted.

I work in video games, and very recently we had a sneaky bug in one of our AAA titles(that was already out!), where(in huge simplification) we had a struct that looked like: struct Obj { int foo; bool bar; } then we were storing those in a custom hashmap using these as keys, where the hashing function was basically hashing bits of each stored object, without any awareness of what's in the object. The bug was found wh…

It's not just the different "under the hood size" that's a problem in this situation, but alignment-padding bytes added by the compiler inbetween struct members will have random junk data in them, the compiler will not zero-initialize padding bytes, unless you explicitely memset() the struct (and even then I wouldn't count on that the padding bytes aren't "tainted" later). E.g. if you initialize a C struct or C++ obj…

Zeroing padding bytes is an interesting scenario. The C++ standard does mandate zeroing padding bytes in certain cases[1], but some compilers do not conform. It's especially a nasty issue when partially overlapping subobjects and RVO are added to the mix. There is a possible defect in the C++ standard here.

[1] https://eel.is/c++draft/dcl.init#6.2

Re: The Lost Art of Structure Packing (2018)

#16
post #7
post #5

Earlier quoted context omitted.

Wait, forgive my ignorance, isn’t this the default? If you don’t care about the memory layout then won’t the compiler reorg / pad structure members to fulfill alignment?

Pad - yes, typically. Reorg - seldom.

Reorg is prohibited by C standard.

Re: The Lost Art of Structure Packing (2018)

#17

Earlier quoted context omitted.

I work in video games, and very recently we had a sneaky bug in one of our AAA titles(that was already out!), where(in huge simplification) we had a struct that looked like: struct Obj { int foo; bool bar; } then we were storing those in a custom hashmap using these as keys, where the hashing function was basically hashing bits of each stored object, without any awareness of what's in the object. The bug was found wh…

In my first job, there was an interesting bug introduced by an un-terminated pragma-pack in a header file. Because not every structure was packed, depending on your include order, some structures would be packed differently in different compilation units. Except, for the only structures this happened for, the packed packing was coincidentally the same as the default packing ... when the program was compiled 32-bits.…

>> some structures would be packed differently in different compilation units.

Re: The Lost Art of Structure Packing (2018)

#18
post #5
post #2

It would be nice if there was an annotation that just lets the compiler do all the optimization for me for the cases where I don't care about the memory layout of the struct. Just like the Rust compiler can do without repr(C)

Wait, forgive my ignorance, isn’t this the default? If you don’t care about the memory layout then won’t the compiler reorg / pad structure members to fulfill alignment?

Unfortunately pointer comparison between addresses of subobjects has a defined order, so reorg is not possible.

Re: The Lost Art of Structure Packing (2018)

#19
post #4

If you do any development that requires touching Win32, structure packing and memory alignment is still very real. I was recently doing that in the context of improving a language’s library support for something that had to go through the OS SDK. I don’t miss the days when that stuff was the norm.

I have done some win32 programming but haven't encountered struct packing or alignment being an issue, where does that pop up?

It's abstracted behind the API's data types as long as you're using C++, but in order to work with the data types you often have to maneuver around the specific packing/alignment. The Windows ETW tracing API has several examples of specific "structure packing" phenomena:

1. Arranging fields to pack things that are shorter than 4 bytes along 4 byte boundaries.

2. Manually arranging data buffers in very specific layouts (this is less about the original post, more about a different interpretation of "packing").

Aside from what I mentioned above, more commonly you will run into this in interop scenarios, such as calling C/C++ API's from C#. Thankfully those scenarios are few and far between.

Re: The Lost Art of Structure Packing (2018)

#20
post #4

Earlier quoted context omitted.

I have done some win32 programming but haven't encountered struct packing or alignment being an issue, where does that pop up?

I work in video games, and very recently we had a sneaky bug in one of our AAA titles(that was already out!), where(in huge simplification) we had a struct that looked like: struct Obj { int foo; bool bar; } then we were storing those in a custom hashmap using these as keys, where the hashing function was basically hashing bits of each stored object, without any awareness of what's in the object. The bug was found wh…

> C++20 now has a "hashable" concept to help with this

I'm sorry, you can easily solve this problem in K&R C from 1979.

Post reply on HN