[HN Gopher] Structures in C: From Basics to Memory Alignment ___________________________________________________________________ Structures in C: From Basics to Memory Alignment Author : aheck Score : 47 points Date : 2023-06-29 21:08 UTC (1 hours ago) (HTM) web link (abstractexpr.com) (TXT) w3m dump (abstractexpr.com) | colonwqbang wrote: | > The only good reason to use packed structures is when you need | to map some memory (e.g. hardware registers exposed to memory) | bit by bit to a structure. | | Another common reason is when two CPUs of different architecture | need to access the same structure in memory. E.g. you have a | RiscV and an Arm64 processor in the same system, sharing memory. | Or you read structured binary data from disk and need to specify | an exact layout. | mananaysiempre wrote: | All of these sound weird to me--most non-stupid (hello 802.2) | protocols and hardware are going to have natural-aligned | structure fields, so basically any mainstream (8-bit-byte, | two's complement, etc.) ABI is going to lay them out the same | way, packed or not. | | As for RV64 and Arm64, the layout rules for same-size scalar | types in their common ABIs are outright identical aren't they? | | We're (most of us) a long way away from the time where each DOS | compiler had its own opinions on whether long double should be | 8-, 16-, 32-, or 64-bit aligned and 80 or 128 bits long. | packetlost wrote: | You assume it was RV64. It could have easily been RV32 | com2kid wrote: | > All of these sound weird to me--most non-stupid (hello | 802.2) protocols and hardware are going to have natural- | aligned structure fields, so basically any mainstream (8-bit- | byte, two's complement, etc.) ABI is going to lay them out | the same way, packed or not. | | In the long ago year of 2015 I worked on a project where the | same binary packet was: | | 1. Generated by an 8 bit micro controller | | 2. Consumed by a 32bit Cortex M3 | | 3. Passed onto iPhones, Androids, Windows Phones, and Windows | PCs running ObjC, Java, C#, and C++ respectively | | 4. Uploaded to a cloud provider | | The phrase "natural aligned" has no meaning in that context. | mananaysiempre wrote: | > The phrase "natural aligned" has no meaning in that | context. | | The phrase "naturally aligned" as I'm accustomed to seeing | it used refers to the alignment of a power-of-two-sized | type (usually a scalar one) being equal to its size. Unless | you're working with, say, 18-bit or 24-bit integers (that | do exist in obscure places), it does have a meaning, and | unless you're using non-eight-bit bytes that meaning is | fairly universal (and if you're not, your I/O is probably | screwed up in hard-to-predict ways[1]). | | At least for your items 2, 3, and 4--excluding Java and C# | which are not relevant to TFA about C and are likely to use | manual packing code--you have, let's see, | | - The bytes are eight bits wide, and ASCII strings have | their usual meaning; | | - The integer types are wraparound unsigned and two's | complement signed least-endian with no padding bits or trap | representations and come in 8-bit, 16-bit, 32-bit, and | 64-bit sizes and identical alignments; | | - The floating-point types are IEEE 754 single and double | precision floats, little endian, respectively 32 bits and | 64 bits in size and of identical alignment, though you | should probably avoid relying on subnormals or the exact | choice of NaNs; | | - Structures and unions have the alignment requirement of | their most strictly aligned member; | | - The members of a structure are laid out at increasing | offsets, with each member starting at the earliest offset | permitted by its alignment (while the members of a union | all start at offset zero as the standard requires); | | - The structure or union is then padded at the end so that | its alignment divides its size. | | If you avoid extended precision and SIMD types, the default | ABI settings should get you completely compatible layouts | here. (On an earlier ARM you might've run into mixed-endian | floats, but not on any Cortex flavour.) Even bitfields | would be entirely fine, except Microsoft _bloody_ Windows | had to be stupid there. | | Honestly the only potential problem is 1, an unspecified | 8-bit micro, and that only because the implicit integer | promotions of standard C make getting decent performance | out of those a bit of a crapshoot, leading to noncompliant | hacks like 8-bit ints or 48-bit long longs. Still, if the | usual complement of 8/16/32/64-bit integers is available, | the worst you're likely to have to do is spell out any | structure padding explicitly. | | [1] https://thephd.dev/conformance-should-mean-something- | fputc-a... | colonwqbang wrote: | > As for RV64 and Arm64 | | This was just a placeholder, perhaps a bad example. I program | a proprietary CPU architecture which does not require | alignment. And for which the compiler naturally prefers to | pack structs. Getting it to mimick Arm style struct padding | is much harder and error prone than just having the Arm pack | everything. | | Maybe you are right and we are heading for a One True Struct | Layout in the future. Today I think it is still too scary to | pass the same unpacked struct declaration to various compiler | archs and hope they come up with the same interpretation. | synergy20 wrote: | pretty cool, love anything related to C. | | might want to add anonymous struct. | | also put function pointers inside struct for simple object- | oriented-programming in C. | | flexible array is handy, you do one malloc for all, but pointers | inside struct is more 'flexible', for example you can put a 'void | *' and cast it to various data types. for flexible array, the | data types must be chosen first. | keyle wrote: | In passing, there is no version of myself that hasn't shot | himself in the foot using `void *` at some point :) | zabzonk wrote: | > Using a Structure via a Pointer | | code that sets the array doesn't use the pointer. ___________________________________________________________________ (page generated 2023-06-29 23:00 UTC)