{"title":"Swift Tuples Drop Their Tail Padding","html_url":"https://deallocatedobjects.com/posts/swift-tuples-drop-their-tail-padding","source_url":"","markdown_content":"[Multimeter](https://multimeterapp.com) can show your Mac's fan speed. There's no public API for that, so it asks the System Management Controller through IOKit: open the `AppleSMC` service, then call `IOConnectCallStructMethod` with a struct going in and the same kind of struct coming back. The struct is `SMCKeyData_t`, and in C it's 80 bytes.\n\nMy first Swift version of that struct was 76 bytes. It compiled, nothing warned, and every call came back `0xe00002c2`, which is `kIOReturnBadArgument`. The cause is a rule about Swift layout that's easy to miss if most of your C interop goes through imported headers: a Swift tuple's size doesn't include its trailing padding, and the next field moves in to fill it.\n\n### The C Struct\n\nHere's the C declaration the SMC expects:\n\n```c title=\"smc.h\"\n#include <stdint.h>\ntypedef struct { char major; char minor; char build; char reserved[1]; uint16_t release; } SMCKeyData_vers_t;\ntypedef struct { uint16_t version; uint16_t length; uint32_t cpuPLimit; uint32_t gpuPLimit; uint32_t memPLimit; } SMCKeyData_pLimitData_t;\ntypedef struct { uint32_t dataSize; uint32_t dataType; char dataAttributes; } SMCKeyData_keyInfo_t;\ntypedef char SMCBytes_t[32];\ntypedef struct {\n  uint32_t key;\n  SMCKeyData_vers_t vers;\n  SMCKeyData_pLimitData_t pLimitData;\n  SMCKeyData_keyInfo_t keyInfo;\n  char result;\n  char status;\n  char data8;\n  uint32_t data32;\n  SMCBytes_t bytes;\n} SMCKeyData_t;\n```\n\nThree of the fields are small structs of their own. A tuple is the obvious way to write those in Swift without declaring three extra types, so that's what I did (`Bytes` is a typealias for a tuple of 32 `UInt8`s):\n\n```swift\nvar key: UInt32 = 0\nvar vers = (UInt8(0), UInt8(0), UInt8(0), UInt8(0), UInt16(0))\nvar pLimitData = (UInt16(0), UInt16(0), UInt32(0), UInt32(0), UInt32(0))\nvar keyInfo = (UInt32(0), UInt32(0), UInt8(0))\nvar result: UInt8 = 0\nvar status: UInt8 = 0\nvar data8: UInt8 = 0\nvar data32: UInt32 = 0\nvar bytes: Bytes = (0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0)\n```\n\n`vers` and `pLimitData` happen to come out right. `keyInfo` doesn't.\n\n### Size, Stride And Alignment\n\n`MemoryLayout` gives you three numbers for any type, and they answer different questions:\n\n- `size` is how many bytes the value's fields occupy, from the start to the end of the last field.\n- `alignment` is the boundary the value has to start on.\n- `stride` is `size` rounded up to a multiple of `alignment`, which is the distance from one element to the next in an array.\n\nFor a `(UInt32, UInt32, UInt8)` tuple, that's:\n\n```swift\ntypealias KeyInfo = (UInt32, UInt32, UInt8)\nprint(MemoryLayout<KeyInfo>.size)      // 9\nprint(MemoryLayout<KeyInfo>.stride)    // 12\nprint(MemoryLayout<KeyInfo>.alignment) // 4\n```\n\nC has one number for this, `sizeof`, and it always includes the tail padding. `sizeof(SMCKeyData_keyInfo_t)` is 12, and a field that comes after a `keyInfo` starts 12 bytes after it.\n\nSwift lays out the fields of a struct differently. Each field goes at the next offset that suits its own alignment after the previous field's `size`. So `result`, a `UInt8` with an alignment of 1, goes at offset 37, right after the tuple's 9 bytes, in the spot C keeps as padding.\n\nThe same thing happens if you declare `keyInfo` as a nested Swift struct with three properties. Its `size` is 9 and the next field lands at 9. Only a struct imported from C keeps C's answer: if Swift sees `SMCKeyData_keyInfo_t` through a header, its `size` is 12.\n\n### Where The Bytes Went\n\nHere are the field offsets from `offsetof` in C next to `MemoryLayout.offset(of:)` for the tuple version:\n\n| Field | C | Swift with a tuple |\n|-------|---|--------------------|\n| `keyInfo` | 28 | 28 |\n| `result` | 40 | 37 |\n| `data32` | 44 | 40 |\n| `bytes` | 48 | 44 |\n| Total | 80 | 76 |\n\nEverything after `keyInfo` is in the wrong place. `result`, `status` and `data8` move up three bytes; `data32` realigns to 40, four bytes early; the 32-byte payload starts at 44 and ends at 76.\n\nThe size alone is enough to get the call rejected. `SMCReader` passes `MemoryLayout<KeyData>.stride` as the input size, and for this version that's 76. On my MacBook Pro running macOS 27, sending a correctly laid out struct with an input size of 76 returns `kIOReturnBadArgument`, and the same struct with 80 succeeds.\n\n### The Fix\n\nIn Multimeter's `SMCReader`, `keyInfo` is now three separate properties with the padding written out:\n\n```swift title=\"Sources/Metrics/SystemReaders.swift\"\n// Mirrors the C SMCKeyData_t (80 bytes). keyInfo is spelled out field by\n// field: as a Swift tuple it loses its tail padding and shifts\n// everything after it by 3 or 4 bytes, and the SMC rejects every call.\nvar key: UInt32 = 0\nvar vers = (UInt8(0), UInt8(0), UInt8(0), UInt8(0), UInt16(0))\nvar pLimitData = (UInt16(0), UInt16(0), UInt32(0), UInt32(0), UInt32(0))\nvar keyInfoDataSize: UInt32 = 0\nvar keyInfoDataType: UInt32 = 0\nvar keyInfoAttributes: UInt8 = 0\nvar keyInfoPadding = (UInt8(0), UInt8(0), UInt8(0))\nvar result: UInt8 = 0\nvar status: UInt8 = 0\nvar data8: UInt8 = 0\nvar data32: UInt32 = 0\nvar bytes: Bytes = (0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0)\n```\n\n`keyInfoPadding` is the part that matters. Flattening the tuple without it would leave the same 76 bytes, since `result` would still sit right after `keyInfoAttributes`. With it, `result` is at 40, `bytes` is at 48, and `MemoryLayout<KeyData>.size` and `.stride` are both 80. The two-step read (key info with `data8 = 9`, then the value with `data8 = 5`) works, and the fan count key `FNum` comes back as a one-byte `ui8 `.\n\n`vers` and `pLimitData` can stay tuples because neither has tail padding: `vers` is 6 bytes with 2-byte alignment and `pLimitData` is 16 with 4-byte alignment. That's luck of the layout, so I'd still check them the same way.\n\n### Checking Against C\n\nYou don't have to work out offsets by hand. Put the header in a tiny C file and ask clang:\n\n```c title=\"size.c\"\n#include <stdio.h>\n#include <stddef.h>\n#include \"smc.h\"\nint main(void) {\n  printf(\"SMCKeyData_t          %zu\\n\", sizeof(SMCKeyData_t));\n  printf(\"SMCKeyData_keyInfo_t  %zu\\n\", sizeof(SMCKeyData_keyInfo_t));\n  printf(\"offsetof keyInfo      %zu\\n\", offsetof(SMCKeyData_t, keyInfo));\n  printf(\"offsetof result       %zu\\n\", offsetof(SMCKeyData_t, result));\n  printf(\"offsetof data32       %zu\\n\", offsetof(SMCKeyData_t, data32));\n  printf(\"offsetof bytes        %zu\\n\", offsetof(SMCKeyData_t, bytes));\n  return 0;\n}\n```\n\n```bash\nclang size.c -o size && ./size\n```\n\nThat prints 80, 12, 28, 40, 44 and 48. On the Swift side, `MemoryLayout<KeyData>.offset(of: \\.bytes)` gives you the same kind of number for any stored property, so you can line the two lists up field by field.\n\n### Mirroring Any C Struct In Swift\n\nThe best option is not to mirror it at all. If you can put the C declaration in a header, Swift imports the struct with C's layout. In an app target that's the bridging header (`SWIFT_OBJC_BRIDGING_HEADER`); in a package or a plain `swiftc` build, a module map works:\n\n```text title=\"SMCShim/module.modulemap\"\nmodule SMCShim {\n    header \"smc.h\"\n    export *\n}\n```\n\nAfter `import SMCShim`, `MemoryLayout<SMCKeyData_t>.size` is 80 and you get named fields like `data.keyInfo.dataSize` for free. The trade is that `char` fields import as `Int8` and the 32-byte array imports as a 32-element tuple of `Int8`.\n\nIf you do write the struct in Swift, avoid tuples and nested Swift structs for any C member that has tail padding, spell those fields out, and add the padding bytes yourself. Then make the layout prove itself. A few preconditions at startup or in a unit test turn a silent `kIOReturnBadArgument` into a crash that names the problem:\n\n```swift\nprecondition(MemoryLayout<KeyData>.stride == 80, \"KeyData is \\(MemoryLayout<KeyData>.stride) bytes, SMCKeyData_t is 80\")\nprecondition(MemoryLayout<KeyData>.offset(of: \\.result) == 40)\nprecondition(MemoryLayout<KeyData>.offset(of: \\.bytes) == 48)\n```\n\nCompare `stride` with `sizeof`, since `stride` is the Swift number that includes tail padding. For `KeyData` the two Swift numbers are both 80, but they often differ: a Swift struct with a `UInt32` followed by a `UInt8` has a `size` of 5 and a `stride` of 8, and C's `sizeof` for the same two fields is 8. The offset checks catch the other case, where fields shift around but the total happens to stay the same.","html_content":"<p><a href=\"https://multimeterapp.com\">Multimeter</a> can show your Mac’s fan speed. There’s no public API for that, so it asks the System Management Controller through IOKit: open the <code>AppleSMC</code> service, then call <code>IOConnectCallStructMethod</code> with a struct going in and the same kind of struct coming back. The struct is <code>SMCKeyData_t</code>, and in C it’s 80 bytes.</p>\n<p>My first Swift version of that struct was 76 bytes. It compiled, nothing warned, and every call came back <code>0xe00002c2</code>, which is <code>kIOReturnBadArgument</code>. The cause is a rule about Swift layout that’s easy to miss if most of your C interop goes through imported headers: a Swift tuple’s size doesn’t include its trailing padding, and the next field moves in to fill it.</p>\n<h2 id=\"the-c-struct\" data-level=\"3\">The C Struct</h2>\n<p>Here’s the C declaration the SMC expects:</p>\n<figure class=\"code\" data-lang=\"c\"><figcaption><span class=\"file\">smc.h</span><span class=\"lang\">C</span></figcaption><pre class=\"shiki shiki-themes github-light github-dark\" style=\"--shiki-light:#24292e;--shiki-dark:#e1e4e8;--shiki-light-bg:#fff;--shiki-dark-bg:#24292e\" tabindex=\"0\"><code><span class=\"line\"><span style=\"--shiki-light:#D73A49;--shiki-dark:#F97583\">#include</span><span style=\"--shiki-light:#032F62;--shiki-dark:#9ECBFF\"> &#x3C;stdint.h></span></span>\n<span class=\"line\"><span style=\"--shiki-light:#D73A49;--shiki-dark:#F97583\">typedef</span><span style=\"--shiki-light:#D73A49;--shiki-dark:#F97583\"> struct</span><span style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\"> { </span><span style=\"--shiki-light:#D73A49;--shiki-dark:#F97583\">char</span><span style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\"> major; </span><span style=\"--shiki-light:#D73A49;--shiki-dark:#F97583\">char</span><span style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\"> minor; </span><span style=\"--shiki-light:#D73A49;--shiki-dark:#F97583\">char</span><span style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\"> build; </span><span style=\"--shiki-light:#D73A49;--shiki-dark:#F97583\">char</span><span style=\"--shiki-light:#E36209;--shiki-dark:#FFAB70\"> reserved</span><span style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\">[</span><span style=\"--shiki-light:#005CC5;--shiki-dark:#79B8FF\">1</span><span style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\">]; </span><span style=\"--shiki-light:#D73A49;--shiki-dark:#F97583\">uint16_t</span><span style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\"> release; } </span><span style=\"--shiki-light:#005CC5;--shiki-dark:#79B8FF\">SMCKeyData_vers_t</span><span style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\">;</span></span>\n<span class=\"line\"><span style=\"--shiki-light:#D73A49;--shiki-dark:#F97583\">typedef</span><span style=\"--shiki-light:#D73A49;--shiki-dark:#F97583\"> struct</span><span style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\"> { </span><span style=\"--shiki-light:#D73A49;--shiki-dark:#F97583\">uint16_t</span><span style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\"> version; </span><span style=\"--shiki-light:#D73A49;--shiki-dark:#F97583\">uint16_t</span><span style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\"> length; </span><span style=\"--shiki-light:#D73A49;--shiki-dark:#F97583\">uint32_t</span><span style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\"> cpuPLimit; </span><span style=\"--shiki-light:#D73A49;--shiki-dark:#F97583\">uint32_t</span><span style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\"> gpuPLimit; </span><span style=\"--shiki-light:#D73A49;--shiki-dark:#F97583\">uint32_t</span><span style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\"> memPLimit; } </span><span style=\"--shiki-light:#005CC5;--shiki-dark:#79B8FF\">SMCKeyData_pLimitData_t</span><span style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\">;</span></span>\n<span class=\"line\"><span style=\"--shiki-light:#D73A49;--shiki-dark:#F97583\">typedef</span><span style=\"--shiki-light:#D73A49;--shiki-dark:#F97583\"> struct</span><span style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\"> { </span><span style=\"--shiki-light:#D73A49;--shiki-dark:#F97583\">uint32_t</span><span style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\"> dataSize; </span><span style=\"--shiki-light:#D73A49;--shiki-dark:#F97583\">uint32_t</span><span style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\"> dataType; </span><span style=\"--shiki-light:#D73A49;--shiki-dark:#F97583\">char</span><span style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\"> dataAttributes; } </span><span style=\"--shiki-light:#005CC5;--shiki-dark:#79B8FF\">SMCKeyData_keyInfo_t</span><span style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\">;</span></span>\n<span class=\"line\"><span style=\"--shiki-light:#D73A49;--shiki-dark:#F97583\">typedef</span><span style=\"--shiki-light:#D73A49;--shiki-dark:#F97583\"> char</span><span style=\"--shiki-light:#005CC5;--shiki-dark:#79B8FF\"> SMCBytes_t</span><span style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\">[</span><span style=\"--shiki-light:#005CC5;--shiki-dark:#79B8FF\">32</span><span style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\">];</span></span>\n<span class=\"line\"><span style=\"--shiki-light:#D73A49;--shiki-dark:#F97583\">typedef</span><span style=\"--shiki-light:#D73A49;--shiki-dark:#F97583\"> struct</span><span style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\"> {</span></span>\n<span class=\"line\"><span style=\"--shiki-light:#D73A49;--shiki-dark:#F97583\">  uint32_t</span><span style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\"> key;</span></span>\n<span class=\"line\"><span style=\"--shiki-light:#005CC5;--shiki-dark:#79B8FF\">  SMCKeyData_vers_t</span><span style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\"> vers;</span></span>\n<span class=\"line\"><span style=\"--shiki-light:#005CC5;--shiki-dark:#79B8FF\">  SMCKeyData_pLimitData_t</span><span style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\"> pLimitData;</span></span>\n<span class=\"line\"><span style=\"--shiki-light:#005CC5;--shiki-dark:#79B8FF\">  SMCKeyData_keyInfo_t</span><span style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\"> keyInfo;</span></span>\n<span class=\"line\"><span style=\"--shiki-light:#D73A49;--shiki-dark:#F97583\">  char</span><span style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\"> result;</span></span>\n<span class=\"line\"><span style=\"--shiki-light:#D73A49;--shiki-dark:#F97583\">  char</span><span style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\"> status;</span></span>\n<span class=\"line\"><span style=\"--shiki-light:#D73A49;--shiki-dark:#F97583\">  char</span><span style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\"> data8;</span></span>\n<span class=\"line\"><span style=\"--shiki-light:#D73A49;--shiki-dark:#F97583\">  uint32_t</span><span style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\"> data32;</span></span>\n<span class=\"line\"><span style=\"--shiki-light:#005CC5;--shiki-dark:#79B8FF\">  SMCBytes_t</span><span style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\"> bytes;</span></span>\n<span class=\"line\"><span style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\">} </span><span style=\"--shiki-light:#005CC5;--shiki-dark:#79B8FF\">SMCKeyData_t</span><span style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\">;</span></span></code></pre></figure><p>Three of the fields are small structs of their own. A tuple is the obvious way to write those in Swift without declaring three extra types, so that’s what I did (<code>Bytes</code> is a typealias for a tuple of 32 <code>UInt8</code>s):</p>\n<figure class=\"code\" data-lang=\"swift\"><figcaption><span class=\"lang\">Swift</span></figcaption><pre class=\"shiki shiki-themes github-light github-dark\" style=\"--shiki-light:#24292e;--shiki-dark:#e1e4e8;--shiki-light-bg:#fff;--shiki-dark-bg:#24292e\" tabindex=\"0\"><code><span class=\"line\"><span style=\"--shiki-light:#D73A49;--shiki-dark:#F97583\">var</span><span style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\"> key: </span><span style=\"--shiki-light:#005CC5;--shiki-dark:#79B8FF\">UInt32</span><span style=\"--shiki-light:#D73A49;--shiki-dark:#F97583\"> =</span><span style=\"--shiki-light:#005CC5;--shiki-dark:#79B8FF\"> 0</span></span>\n<span class=\"line\"><span style=\"--shiki-light:#D73A49;--shiki-dark:#F97583\">var</span><span style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\"> vers </span><span style=\"--shiki-light:#D73A49;--shiki-dark:#F97583\">=</span><span style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\"> (</span><span style=\"--shiki-light:#005CC5;--shiki-dark:#79B8FF\">UInt8</span><span style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\">(</span><span style=\"--shiki-light:#005CC5;--shiki-dark:#79B8FF\">0</span><span style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\">), </span><span style=\"--shiki-light:#005CC5;--shiki-dark:#79B8FF\">UInt8</span><span style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\">(</span><span style=\"--shiki-light:#005CC5;--shiki-dark:#79B8FF\">0</span><span style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\">), </span><span style=\"--shiki-light:#005CC5;--shiki-dark:#79B8FF\">UInt8</span><span style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\">(</span><span style=\"--shiki-light:#005CC5;--shiki-dark:#79B8FF\">0</span><span style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\">), </span><span style=\"--shiki-light:#005CC5;--shiki-dark:#79B8FF\">UInt8</span><span style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\">(</span><span style=\"--shiki-light:#005CC5;--shiki-dark:#79B8FF\">0</span><span style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\">), </span><span style=\"--shiki-light:#005CC5;--shiki-dark:#79B8FF\">UInt16</span><span style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\">(</span><span style=\"--shiki-light:#005CC5;--shiki-dark:#79B8FF\">0</span><span style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\">))</span></span>\n<span class=\"line\"><span style=\"--shiki-light:#D73A49;--shiki-dark:#F97583\">var</span><span style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\"> pLimitData </span><span style=\"--shiki-light:#D73A49;--shiki-dark:#F97583\">=</span><span style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\"> (</span><span style=\"--shiki-light:#005CC5;--shiki-dark:#79B8FF\">UInt16</span><span style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\">(</span><span style=\"--shiki-light:#005CC5;--shiki-dark:#79B8FF\">0</span><span style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\">), </span><span style=\"--shiki-light:#005CC5;--shiki-dark:#79B8FF\">UInt16</span><span style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\">(</span><span style=\"--shiki-light:#005CC5;--shiki-dark:#79B8FF\">0</span><span style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\">), </span><span style=\"--shiki-light:#005CC5;--shiki-dark:#79B8FF\">UInt32</span><span style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\">(</span><span style=\"--shiki-light:#005CC5;--shiki-dark:#79B8FF\">0</span><span style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\">), </span><span style=\"--shiki-light:#005CC5;--shiki-dark:#79B8FF\">UInt32</span><span style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\">(</span><span style=\"--shiki-light:#005CC5;--shiki-dark:#79B8FF\">0</span><span style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\">), </span><span style=\"--shiki-light:#005CC5;--shiki-dark:#79B8FF\">UInt32</span><span style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\">(</span><span style=\"--shiki-light:#005CC5;--shiki-dark:#79B8FF\">0</span><span style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\">))</span></span>\n<span class=\"line\"><span style=\"--shiki-light:#D73A49;--shiki-dark:#F97583\">var</span><span style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\"> keyInfo </span><span style=\"--shiki-light:#D73A49;--shiki-dark:#F97583\">=</span><span style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\"> (</span><span style=\"--shiki-light:#005CC5;--shiki-dark:#79B8FF\">UInt32</span><span style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\">(</span><span style=\"--shiki-light:#005CC5;--shiki-dark:#79B8FF\">0</span><span style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\">), </span><span style=\"--shiki-light:#005CC5;--shiki-dark:#79B8FF\">UInt32</span><span style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\">(</span><span style=\"--shiki-light:#005CC5;--shiki-dark:#79B8FF\">0</span><span style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\">), </span><span style=\"--shiki-light:#005CC5;--shiki-dark:#79B8FF\">UInt8</span><span style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\">(</span><span style=\"--shiki-light:#005CC5;--shiki-dark:#79B8FF\">0</span><span style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\">))</span></span>\n<span class=\"line\"><span style=\"--shiki-light:#D73A49;--shiki-dark:#F97583\">var</span><span style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\"> result: </span><span style=\"--shiki-light:#005CC5;--shiki-dark:#79B8FF\">UInt8</span><span style=\"--shiki-light:#D73A49;--shiki-dark:#F97583\"> =</span><span style=\"--shiki-light:#005CC5;--shiki-dark:#79B8FF\"> 0</span></span>\n<span class=\"line\"><span style=\"--shiki-light:#D73A49;--shiki-dark:#F97583\">var</span><span style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\"> status: </span><span style=\"--shiki-light:#005CC5;--shiki-dark:#79B8FF\">UInt8</span><span style=\"--shiki-light:#D73A49;--shiki-dark:#F97583\"> =</span><span style=\"--shiki-light:#005CC5;--shiki-dark:#79B8FF\"> 0</span></span>\n<span class=\"line\"><span style=\"--shiki-light:#D73A49;--shiki-dark:#F97583\">var</span><span style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\"> data8: </span><span style=\"--shiki-light:#005CC5;--shiki-dark:#79B8FF\">UInt8</span><span style=\"--shiki-light:#D73A49;--shiki-dark:#F97583\"> =</span><span style=\"--shiki-light:#005CC5;--shiki-dark:#79B8FF\"> 0</span></span>\n<span class=\"line\"><span style=\"--shiki-light:#D73A49;--shiki-dark:#F97583\">var</span><span style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\"> data32: </span><span style=\"--shiki-light:#005CC5;--shiki-dark:#79B8FF\">UInt32</span><span style=\"--shiki-light:#D73A49;--shiki-dark:#F97583\"> =</span><span style=\"--shiki-light:#005CC5;--shiki-dark:#79B8FF\"> 0</span></span>\n<span class=\"line\"><span style=\"--shiki-light:#D73A49;--shiki-dark:#F97583\">var</span><span style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\"> bytes: Bytes </span><span style=\"--shiki-light:#D73A49;--shiki-dark:#F97583\">=</span><span style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\"> (</span><span style=\"--shiki-light:#005CC5;--shiki-dark:#79B8FF\">0</span><span style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\">, </span><span style=\"--shiki-light:#005CC5;--shiki-dark:#79B8FF\">0</span><span style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\">, </span><span style=\"--shiki-light:#005CC5;--shiki-dark:#79B8FF\">0</span><span style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\">, </span><span style=\"--shiki-light:#005CC5;--shiki-dark:#79B8FF\">0</span><span style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\">, </span><span style=\"--shiki-light:#005CC5;--shiki-dark:#79B8FF\">0</span><span style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\">, </span><span style=\"--shiki-light:#005CC5;--shiki-dark:#79B8FF\">0</span><span style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\">, </span><span style=\"--shiki-light:#005CC5;--shiki-dark:#79B8FF\">0</span><span style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\">, </span><span style=\"--shiki-light:#005CC5;--shiki-dark:#79B8FF\">0</span><span style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\">, </span><span style=\"--shiki-light:#005CC5;--shiki-dark:#79B8FF\">0</span><span style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\">, </span><span style=\"--shiki-light:#005CC5;--shiki-dark:#79B8FF\">0</span><span style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\">, </span><span style=\"--shiki-light:#005CC5;--shiki-dark:#79B8FF\">0</span><span style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\">, </span><span style=\"--shiki-light:#005CC5;--shiki-dark:#79B8FF\">0</span><span style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\">, </span><span style=\"--shiki-light:#005CC5;--shiki-dark:#79B8FF\">0</span><span style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\">, </span><span style=\"--shiki-light:#005CC5;--shiki-dark:#79B8FF\">0</span><span style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\">, </span><span style=\"--shiki-light:#005CC5;--shiki-dark:#79B8FF\">0</span><span style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\">, </span><span style=\"--shiki-light:#005CC5;--shiki-dark:#79B8FF\">0</span><span style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\">, </span><span style=\"--shiki-light:#005CC5;--shiki-dark:#79B8FF\">0</span><span style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\">, </span><span style=\"--shiki-light:#005CC5;--shiki-dark:#79B8FF\">0</span><span style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\">, </span><span style=\"--shiki-light:#005CC5;--shiki-dark:#79B8FF\">0</span><span style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\">, </span><span style=\"--shiki-light:#005CC5;--shiki-dark:#79B8FF\">0</span><span style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\">, </span><span style=\"--shiki-light:#005CC5;--shiki-dark:#79B8FF\">0</span><span style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\">, </span><span style=\"--shiki-light:#005CC5;--shiki-dark:#79B8FF\">0</span><span style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\">, </span><span style=\"--shiki-light:#005CC5;--shiki-dark:#79B8FF\">0</span><span style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\">, </span><span style=\"--shiki-light:#005CC5;--shiki-dark:#79B8FF\">0</span><span style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\">, </span><span style=\"--shiki-light:#005CC5;--shiki-dark:#79B8FF\">0</span><span style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\">, </span><span style=\"--shiki-light:#005CC5;--shiki-dark:#79B8FF\">0</span><span style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\">, </span><span style=\"--shiki-light:#005CC5;--shiki-dark:#79B8FF\">0</span><span style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\">, </span><span style=\"--shiki-light:#005CC5;--shiki-dark:#79B8FF\">0</span><span style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\">, </span><span style=\"--shiki-light:#005CC5;--shiki-dark:#79B8FF\">0</span><span style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\">, </span><span style=\"--shiki-light:#005CC5;--shiki-dark:#79B8FF\">0</span><span style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\">, </span><span style=\"--shiki-light:#005CC5;--shiki-dark:#79B8FF\">0</span><span style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\">, </span><span style=\"--shiki-light:#005CC5;--shiki-dark:#79B8FF\">0</span><span style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\">)</span></span></code></pre></figure><p><code>vers</code> and <code>pLimitData</code> happen to come out right. <code>keyInfo</code> doesn’t.</p>\n<h2 id=\"size-stride-and-alignment\" data-level=\"3\">Size, Stride And Alignment</h2>\n<p><code>MemoryLayout</code> gives you three numbers for any type, and they answer different questions:</p>\n<ul>\n<li><code>size</code> is how many bytes the value’s fields occupy, from the start to the end of the last field.</li>\n<li><code>alignment</code> is the boundary the value has to start on.</li>\n<li><code>stride</code> is <code>size</code> rounded up to a multiple of <code>alignment</code>, which is the distance from one element to the next in an array.</li>\n</ul>\n<p>For a <code>(UInt32, UInt32, UInt8)</code> tuple, that’s:</p>\n<figure class=\"code\" data-lang=\"swift\"><figcaption><span class=\"lang\">Swift</span></figcaption><pre class=\"shiki shiki-themes github-light github-dark\" style=\"--shiki-light:#24292e;--shiki-dark:#e1e4e8;--shiki-light-bg:#fff;--shiki-dark-bg:#24292e\" tabindex=\"0\"><code><span class=\"line\"><span style=\"--shiki-light:#D73A49;--shiki-dark:#F97583\">typealias</span><span style=\"--shiki-light:#6F42C1;--shiki-dark:#B392F0\"> KeyInfo</span><span style=\"--shiki-light:#D73A49;--shiki-dark:#F97583\"> =</span><span style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\"> (</span><span style=\"--shiki-light:#005CC5;--shiki-dark:#79B8FF\">UInt32</span><span style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\">, </span><span style=\"--shiki-light:#005CC5;--shiki-dark:#79B8FF\">UInt32</span><span style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\">, </span><span style=\"--shiki-light:#005CC5;--shiki-dark:#79B8FF\">UInt8</span><span style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\">)</span></span>\n<span class=\"line\"><span style=\"--shiki-light:#005CC5;--shiki-dark:#79B8FF\">print</span><span style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\">(</span><span style=\"--shiki-light:#005CC5;--shiki-dark:#79B8FF\">MemoryLayout</span><span style=\"--shiki-light:#D73A49;--shiki-dark:#F97583\">&#x3C;</span><span style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\">KeyInfo</span><span style=\"--shiki-light:#D73A49;--shiki-dark:#F97583\">></span><span style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\">.</span><span style=\"--shiki-light:#005CC5;--shiki-dark:#79B8FF\">size</span><span style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\">)      </span><span style=\"--shiki-light:#6A737D;--shiki-dark:#6A737D\">// 9</span></span>\n<span class=\"line\"><span style=\"--shiki-light:#005CC5;--shiki-dark:#79B8FF\">print</span><span style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\">(</span><span style=\"--shiki-light:#005CC5;--shiki-dark:#79B8FF\">MemoryLayout</span><span style=\"--shiki-light:#D73A49;--shiki-dark:#F97583\">&#x3C;</span><span style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\">KeyInfo</span><span style=\"--shiki-light:#D73A49;--shiki-dark:#F97583\">></span><span style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\">.</span><span style=\"--shiki-light:#005CC5;--shiki-dark:#79B8FF\">stride</span><span style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\">)    </span><span style=\"--shiki-light:#6A737D;--shiki-dark:#6A737D\">// 12</span></span>\n<span class=\"line\"><span style=\"--shiki-light:#005CC5;--shiki-dark:#79B8FF\">print</span><span style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\">(</span><span style=\"--shiki-light:#005CC5;--shiki-dark:#79B8FF\">MemoryLayout</span><span style=\"--shiki-light:#D73A49;--shiki-dark:#F97583\">&#x3C;</span><span style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\">KeyInfo</span><span style=\"--shiki-light:#D73A49;--shiki-dark:#F97583\">></span><span style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\">.</span><span style=\"--shiki-light:#005CC5;--shiki-dark:#79B8FF\">alignment</span><span style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\">) </span><span style=\"--shiki-light:#6A737D;--shiki-dark:#6A737D\">// 4</span></span></code></pre></figure><p>C has one number for this, <code>sizeof</code>, and it always includes the tail padding. <code>sizeof(SMCKeyData_keyInfo_t)</code> is 12, and a field that comes after a <code>keyInfo</code> starts 12 bytes after it.</p>\n<p>Swift lays out the fields of a struct differently. Each field goes at the next offset that suits its own alignment after the previous field’s <code>size</code>. So <code>result</code>, a <code>UInt8</code> with an alignment of 1, goes at offset 37, right after the tuple’s 9 bytes, in the spot C keeps as padding.</p>\n<p>The same thing happens if you declare <code>keyInfo</code> as a nested Swift struct with three properties. Its <code>size</code> is 9 and the next field lands at 9. Only a struct imported from C keeps C’s answer: if Swift sees <code>SMCKeyData_keyInfo_t</code> through a header, its <code>size</code> is 12.</p>\n<h2 id=\"where-the-bytes-went\" data-level=\"3\">Where The Bytes Went</h2>\n<p>Here are the field offsets from <code>offsetof</code> in C next to <code>MemoryLayout.offset(of:)</code> for the tuple version:</p>\n<table>\n<thead>\n<tr>\n<th>Field</th>\n<th>C</th>\n<th>Swift with a tuple</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td><code>keyInfo</code></td>\n<td>28</td>\n<td>28</td>\n</tr>\n<tr>\n<td><code>result</code></td>\n<td>40</td>\n<td>37</td>\n</tr>\n<tr>\n<td><code>data32</code></td>\n<td>44</td>\n<td>40</td>\n</tr>\n<tr>\n<td><code>bytes</code></td>\n<td>48</td>\n<td>44</td>\n</tr>\n<tr>\n<td>Total</td>\n<td>80</td>\n<td>76</td>\n</tr>\n</tbody>\n</table>\n<p>Everything after <code>keyInfo</code> is in the wrong place. <code>result</code>, <code>status</code> and <code>data8</code> move up three bytes; <code>data32</code> realigns to 40, four bytes early; the 32-byte payload starts at 44 and ends at 76.</p>\n<p>The size alone is enough to get the call rejected. <code>SMCReader</code> passes <code>MemoryLayout&lt;KeyData&gt;.stride</code> as the input size, and for this version that’s 76. On my MacBook Pro running macOS 27, sending a correctly laid out struct with an input size of 76 returns <code>kIOReturnBadArgument</code>, and the same struct with 80 succeeds.</p>\n<h2 id=\"the-fix\" data-level=\"3\">The Fix</h2>\n<p>In Multimeter’s <code>SMCReader</code>, <code>keyInfo</code> is now three separate properties with the padding written out:</p>\n<figure class=\"code\" data-lang=\"swift\"><figcaption><span class=\"file\">Sources/Metrics/SystemReaders.swift</span><span class=\"lang\">Swift</span></figcaption><pre class=\"shiki shiki-themes github-light github-dark\" style=\"--shiki-light:#24292e;--shiki-dark:#e1e4e8;--shiki-light-bg:#fff;--shiki-dark-bg:#24292e\" tabindex=\"0\"><code><span class=\"line\"><span style=\"--shiki-light:#6A737D;--shiki-dark:#6A737D\">// Mirrors the C SMCKeyData_t (80 bytes). keyInfo is spelled out field by</span></span>\n<span class=\"line\"><span style=\"--shiki-light:#6A737D;--shiki-dark:#6A737D\">// field: as a Swift tuple it loses its tail padding and shifts</span></span>\n<span class=\"line\"><span style=\"--shiki-light:#6A737D;--shiki-dark:#6A737D\">// everything after it by 3 or 4 bytes, and the SMC rejects every call.</span></span>\n<span class=\"line\"><span style=\"--shiki-light:#D73A49;--shiki-dark:#F97583\">var</span><span style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\"> key: </span><span style=\"--shiki-light:#005CC5;--shiki-dark:#79B8FF\">UInt32</span><span style=\"--shiki-light:#D73A49;--shiki-dark:#F97583\"> =</span><span style=\"--shiki-light:#005CC5;--shiki-dark:#79B8FF\"> 0</span></span>\n<span class=\"line\"><span style=\"--shiki-light:#D73A49;--shiki-dark:#F97583\">var</span><span style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\"> vers </span><span style=\"--shiki-light:#D73A49;--shiki-dark:#F97583\">=</span><span style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\"> (</span><span style=\"--shiki-light:#005CC5;--shiki-dark:#79B8FF\">UInt8</span><span style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\">(</span><span style=\"--shiki-light:#005CC5;--shiki-dark:#79B8FF\">0</span><span style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\">), </span><span style=\"--shiki-light:#005CC5;--shiki-dark:#79B8FF\">UInt8</span><span style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\">(</span><span style=\"--shiki-light:#005CC5;--shiki-dark:#79B8FF\">0</span><span style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\">), </span><span style=\"--shiki-light:#005CC5;--shiki-dark:#79B8FF\">UInt8</span><span style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\">(</span><span style=\"--shiki-light:#005CC5;--shiki-dark:#79B8FF\">0</span><span style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\">), </span><span style=\"--shiki-light:#005CC5;--shiki-dark:#79B8FF\">UInt8</span><span style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\">(</span><span style=\"--shiki-light:#005CC5;--shiki-dark:#79B8FF\">0</span><span style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\">), </span><span style=\"--shiki-light:#005CC5;--shiki-dark:#79B8FF\">UInt16</span><span style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\">(</span><span style=\"--shiki-light:#005CC5;--shiki-dark:#79B8FF\">0</span><span style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\">))</span></span>\n<span class=\"line\"><span style=\"--shiki-light:#D73A49;--shiki-dark:#F97583\">var</span><span style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\"> pLimitData </span><span style=\"--shiki-light:#D73A49;--shiki-dark:#F97583\">=</span><span style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\"> (</span><span style=\"--shiki-light:#005CC5;--shiki-dark:#79B8FF\">UInt16</span><span style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\">(</span><span style=\"--shiki-light:#005CC5;--shiki-dark:#79B8FF\">0</span><span style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\">), </span><span style=\"--shiki-light:#005CC5;--shiki-dark:#79B8FF\">UInt16</span><span style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\">(</span><span style=\"--shiki-light:#005CC5;--shiki-dark:#79B8FF\">0</span><span style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\">), </span><span style=\"--shiki-light:#005CC5;--shiki-dark:#79B8FF\">UInt32</span><span style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\">(</span><span style=\"--shiki-light:#005CC5;--shiki-dark:#79B8FF\">0</span><span style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\">), </span><span style=\"--shiki-light:#005CC5;--shiki-dark:#79B8FF\">UInt32</span><span style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\">(</span><span style=\"--shiki-light:#005CC5;--shiki-dark:#79B8FF\">0</span><span style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\">), </span><span style=\"--shiki-light:#005CC5;--shiki-dark:#79B8FF\">UInt32</span><span style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\">(</span><span style=\"--shiki-light:#005CC5;--shiki-dark:#79B8FF\">0</span><span style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\">))</span></span>\n<span class=\"line\"><span style=\"--shiki-light:#D73A49;--shiki-dark:#F97583\">var</span><span style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\"> keyInfoDataSize: </span><span style=\"--shiki-light:#005CC5;--shiki-dark:#79B8FF\">UInt32</span><span style=\"--shiki-light:#D73A49;--shiki-dark:#F97583\"> =</span><span style=\"--shiki-light:#005CC5;--shiki-dark:#79B8FF\"> 0</span></span>\n<span class=\"line\"><span style=\"--shiki-light:#D73A49;--shiki-dark:#F97583\">var</span><span style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\"> keyInfoDataType: </span><span style=\"--shiki-light:#005CC5;--shiki-dark:#79B8FF\">UInt32</span><span style=\"--shiki-light:#D73A49;--shiki-dark:#F97583\"> =</span><span style=\"--shiki-light:#005CC5;--shiki-dark:#79B8FF\"> 0</span></span>\n<span class=\"line\"><span style=\"--shiki-light:#D73A49;--shiki-dark:#F97583\">var</span><span style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\"> keyInfoAttributes: </span><span style=\"--shiki-light:#005CC5;--shiki-dark:#79B8FF\">UInt8</span><span style=\"--shiki-light:#D73A49;--shiki-dark:#F97583\"> =</span><span style=\"--shiki-light:#005CC5;--shiki-dark:#79B8FF\"> 0</span></span>\n<span class=\"line\"><span style=\"--shiki-light:#D73A49;--shiki-dark:#F97583\">var</span><span style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\"> keyInfoPadding </span><span style=\"--shiki-light:#D73A49;--shiki-dark:#F97583\">=</span><span style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\"> (</span><span style=\"--shiki-light:#005CC5;--shiki-dark:#79B8FF\">UInt8</span><span style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\">(</span><span style=\"--shiki-light:#005CC5;--shiki-dark:#79B8FF\">0</span><span style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\">), </span><span style=\"--shiki-light:#005CC5;--shiki-dark:#79B8FF\">UInt8</span><span style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\">(</span><span style=\"--shiki-light:#005CC5;--shiki-dark:#79B8FF\">0</span><span style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\">), </span><span style=\"--shiki-light:#005CC5;--shiki-dark:#79B8FF\">UInt8</span><span style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\">(</span><span style=\"--shiki-light:#005CC5;--shiki-dark:#79B8FF\">0</span><span style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\">))</span></span>\n<span class=\"line\"><span style=\"--shiki-light:#D73A49;--shiki-dark:#F97583\">var</span><span style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\"> result: </span><span style=\"--shiki-light:#005CC5;--shiki-dark:#79B8FF\">UInt8</span><span style=\"--shiki-light:#D73A49;--shiki-dark:#F97583\"> =</span><span style=\"--shiki-light:#005CC5;--shiki-dark:#79B8FF\"> 0</span></span>\n<span class=\"line\"><span style=\"--shiki-light:#D73A49;--shiki-dark:#F97583\">var</span><span style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\"> status: </span><span style=\"--shiki-light:#005CC5;--shiki-dark:#79B8FF\">UInt8</span><span style=\"--shiki-light:#D73A49;--shiki-dark:#F97583\"> =</span><span style=\"--shiki-light:#005CC5;--shiki-dark:#79B8FF\"> 0</span></span>\n<span class=\"line\"><span style=\"--shiki-light:#D73A49;--shiki-dark:#F97583\">var</span><span style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\"> data8: </span><span style=\"--shiki-light:#005CC5;--shiki-dark:#79B8FF\">UInt8</span><span style=\"--shiki-light:#D73A49;--shiki-dark:#F97583\"> =</span><span style=\"--shiki-light:#005CC5;--shiki-dark:#79B8FF\"> 0</span></span>\n<span class=\"line\"><span style=\"--shiki-light:#D73A49;--shiki-dark:#F97583\">var</span><span style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\"> data32: </span><span style=\"--shiki-light:#005CC5;--shiki-dark:#79B8FF\">UInt32</span><span style=\"--shiki-light:#D73A49;--shiki-dark:#F97583\"> =</span><span style=\"--shiki-light:#005CC5;--shiki-dark:#79B8FF\"> 0</span></span>\n<span class=\"line\"><span style=\"--shiki-light:#D73A49;--shiki-dark:#F97583\">var</span><span style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\"> bytes: Bytes </span><span style=\"--shiki-light:#D73A49;--shiki-dark:#F97583\">=</span><span style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\"> (</span><span style=\"--shiki-light:#005CC5;--shiki-dark:#79B8FF\">0</span><span style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\">, </span><span style=\"--shiki-light:#005CC5;--shiki-dark:#79B8FF\">0</span><span style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\">, </span><span style=\"--shiki-light:#005CC5;--shiki-dark:#79B8FF\">0</span><span style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\">, </span><span style=\"--shiki-light:#005CC5;--shiki-dark:#79B8FF\">0</span><span style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\">, </span><span style=\"--shiki-light:#005CC5;--shiki-dark:#79B8FF\">0</span><span style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\">, </span><span style=\"--shiki-light:#005CC5;--shiki-dark:#79B8FF\">0</span><span style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\">, </span><span style=\"--shiki-light:#005CC5;--shiki-dark:#79B8FF\">0</span><span style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\">, </span><span style=\"--shiki-light:#005CC5;--shiki-dark:#79B8FF\">0</span><span style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\">, </span><span style=\"--shiki-light:#005CC5;--shiki-dark:#79B8FF\">0</span><span style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\">, </span><span style=\"--shiki-light:#005CC5;--shiki-dark:#79B8FF\">0</span><span style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\">, </span><span style=\"--shiki-light:#005CC5;--shiki-dark:#79B8FF\">0</span><span style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\">, </span><span style=\"--shiki-light:#005CC5;--shiki-dark:#79B8FF\">0</span><span style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\">, </span><span style=\"--shiki-light:#005CC5;--shiki-dark:#79B8FF\">0</span><span style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\">, </span><span style=\"--shiki-light:#005CC5;--shiki-dark:#79B8FF\">0</span><span style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\">, </span><span style=\"--shiki-light:#005CC5;--shiki-dark:#79B8FF\">0</span><span style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\">, </span><span style=\"--shiki-light:#005CC5;--shiki-dark:#79B8FF\">0</span><span style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\">, </span><span style=\"--shiki-light:#005CC5;--shiki-dark:#79B8FF\">0</span><span style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\">, </span><span style=\"--shiki-light:#005CC5;--shiki-dark:#79B8FF\">0</span><span style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\">, </span><span style=\"--shiki-light:#005CC5;--shiki-dark:#79B8FF\">0</span><span style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\">, </span><span style=\"--shiki-light:#005CC5;--shiki-dark:#79B8FF\">0</span><span style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\">, </span><span style=\"--shiki-light:#005CC5;--shiki-dark:#79B8FF\">0</span><span style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\">, </span><span style=\"--shiki-light:#005CC5;--shiki-dark:#79B8FF\">0</span><span style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\">, </span><span style=\"--shiki-light:#005CC5;--shiki-dark:#79B8FF\">0</span><span style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\">, </span><span style=\"--shiki-light:#005CC5;--shiki-dark:#79B8FF\">0</span><span style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\">, </span><span style=\"--shiki-light:#005CC5;--shiki-dark:#79B8FF\">0</span><span style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\">, </span><span style=\"--shiki-light:#005CC5;--shiki-dark:#79B8FF\">0</span><span style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\">, </span><span style=\"--shiki-light:#005CC5;--shiki-dark:#79B8FF\">0</span><span style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\">, </span><span style=\"--shiki-light:#005CC5;--shiki-dark:#79B8FF\">0</span><span style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\">, </span><span style=\"--shiki-light:#005CC5;--shiki-dark:#79B8FF\">0</span><span style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\">, </span><span style=\"--shiki-light:#005CC5;--shiki-dark:#79B8FF\">0</span><span style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\">, </span><span style=\"--shiki-light:#005CC5;--shiki-dark:#79B8FF\">0</span><span style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\">, </span><span style=\"--shiki-light:#005CC5;--shiki-dark:#79B8FF\">0</span><span style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\">)</span></span></code></pre></figure><p><code>keyInfoPadding</code> is the part that matters. Flattening the tuple without it would leave the same 76 bytes, since <code>result</code> would still sit right after <code>keyInfoAttributes</code>. With it, <code>result</code> is at 40, <code>bytes</code> is at 48, and <code>MemoryLayout&lt;KeyData&gt;.size</code> and <code>.stride</code> are both 80. The two-step read (key info with <code>data8 = 9</code>, then the value with <code>data8 = 5</code>) works, and the fan count key <code>FNum</code> comes back as a one-byte <code>ui8 </code>.</p>\n<p><code>vers</code> and <code>pLimitData</code> can stay tuples because neither has tail padding: <code>vers</code> is 6 bytes with 2-byte alignment and <code>pLimitData</code> is 16 with 4-byte alignment. That’s luck of the layout, so I’d still check them the same way.</p>\n<h2 id=\"checking-against-c\" data-level=\"3\">Checking Against C</h2>\n<p>You don’t have to work out offsets by hand. Put the header in a tiny C file and ask clang:</p>\n<figure class=\"code\" data-lang=\"c\"><figcaption><span class=\"file\">size.c</span><span class=\"lang\">C</span></figcaption><pre class=\"shiki shiki-themes github-light github-dark\" style=\"--shiki-light:#24292e;--shiki-dark:#e1e4e8;--shiki-light-bg:#fff;--shiki-dark-bg:#24292e\" tabindex=\"0\"><code><span class=\"line\"><span style=\"--shiki-light:#D73A49;--shiki-dark:#F97583\">#include</span><span style=\"--shiki-light:#032F62;--shiki-dark:#9ECBFF\"> &#x3C;stdio.h></span></span>\n<span class=\"line\"><span style=\"--shiki-light:#D73A49;--shiki-dark:#F97583\">#include</span><span style=\"--shiki-light:#032F62;--shiki-dark:#9ECBFF\"> &#x3C;stddef.h></span></span>\n<span class=\"line\"><span style=\"--shiki-light:#D73A49;--shiki-dark:#F97583\">#include</span><span style=\"--shiki-light:#032F62;--shiki-dark:#9ECBFF\"> \"smc.h\"</span></span>\n<span class=\"line\"><span style=\"--shiki-light:#D73A49;--shiki-dark:#F97583\">int</span><span style=\"--shiki-light:#6F42C1;--shiki-dark:#B392F0\"> main</span><span style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\">(</span><span style=\"--shiki-light:#D73A49;--shiki-dark:#F97583\">void</span><span style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\">) {</span></span>\n<span class=\"line\"><span style=\"--shiki-light:#6F42C1;--shiki-dark:#B392F0\">  printf</span><span style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\">(</span><span style=\"--shiki-light:#032F62;--shiki-dark:#9ECBFF\">\"SMCKeyData_t          </span><span style=\"--shiki-light:#005CC5;--shiki-dark:#79B8FF\">%zu\\n</span><span style=\"--shiki-light:#032F62;--shiki-dark:#9ECBFF\">\"</span><span style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\">, </span><span style=\"--shiki-light:#D73A49;--shiki-dark:#F97583\">sizeof</span><span style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\">(</span><span style=\"--shiki-light:#005CC5;--shiki-dark:#79B8FF\">SMCKeyData_t</span><span style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\">));</span></span>\n<span class=\"line\"><span style=\"--shiki-light:#6F42C1;--shiki-dark:#B392F0\">  printf</span><span style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\">(</span><span style=\"--shiki-light:#032F62;--shiki-dark:#9ECBFF\">\"SMCKeyData_keyInfo_t  </span><span style=\"--shiki-light:#005CC5;--shiki-dark:#79B8FF\">%zu\\n</span><span style=\"--shiki-light:#032F62;--shiki-dark:#9ECBFF\">\"</span><span style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\">, </span><span style=\"--shiki-light:#D73A49;--shiki-dark:#F97583\">sizeof</span><span style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\">(</span><span style=\"--shiki-light:#005CC5;--shiki-dark:#79B8FF\">SMCKeyData_keyInfo_t</span><span style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\">));</span></span>\n<span class=\"line\"><span style=\"--shiki-light:#6F42C1;--shiki-dark:#B392F0\">  printf</span><span style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\">(</span><span style=\"--shiki-light:#032F62;--shiki-dark:#9ECBFF\">\"offsetof keyInfo      </span><span style=\"--shiki-light:#005CC5;--shiki-dark:#79B8FF\">%zu\\n</span><span style=\"--shiki-light:#032F62;--shiki-dark:#9ECBFF\">\"</span><span style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\">, </span><span style=\"--shiki-light:#6F42C1;--shiki-dark:#B392F0\">offsetof</span><span style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\">(</span><span style=\"--shiki-light:#005CC5;--shiki-dark:#79B8FF\">SMCKeyData_t</span><span style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\">, keyInfo));</span></span>\n<span class=\"line\"><span style=\"--shiki-light:#6F42C1;--shiki-dark:#B392F0\">  printf</span><span style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\">(</span><span style=\"--shiki-light:#032F62;--shiki-dark:#9ECBFF\">\"offsetof result       </span><span style=\"--shiki-light:#005CC5;--shiki-dark:#79B8FF\">%zu\\n</span><span style=\"--shiki-light:#032F62;--shiki-dark:#9ECBFF\">\"</span><span style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\">, </span><span style=\"--shiki-light:#6F42C1;--shiki-dark:#B392F0\">offsetof</span><span style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\">(</span><span style=\"--shiki-light:#005CC5;--shiki-dark:#79B8FF\">SMCKeyData_t</span><span style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\">, result));</span></span>\n<span class=\"line\"><span style=\"--shiki-light:#6F42C1;--shiki-dark:#B392F0\">  printf</span><span style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\">(</span><span style=\"--shiki-light:#032F62;--shiki-dark:#9ECBFF\">\"offsetof data32       </span><span style=\"--shiki-light:#005CC5;--shiki-dark:#79B8FF\">%zu\\n</span><span style=\"--shiki-light:#032F62;--shiki-dark:#9ECBFF\">\"</span><span style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\">, </span><span style=\"--shiki-light:#6F42C1;--shiki-dark:#B392F0\">offsetof</span><span style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\">(</span><span style=\"--shiki-light:#005CC5;--shiki-dark:#79B8FF\">SMCKeyData_t</span><span style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\">, data32));</span></span>\n<span class=\"line\"><span style=\"--shiki-light:#6F42C1;--shiki-dark:#B392F0\">  printf</span><span style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\">(</span><span style=\"--shiki-light:#032F62;--shiki-dark:#9ECBFF\">\"offsetof bytes        </span><span style=\"--shiki-light:#005CC5;--shiki-dark:#79B8FF\">%zu\\n</span><span style=\"--shiki-light:#032F62;--shiki-dark:#9ECBFF\">\"</span><span style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\">, </span><span style=\"--shiki-light:#6F42C1;--shiki-dark:#B392F0\">offsetof</span><span style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\">(</span><span style=\"--shiki-light:#005CC5;--shiki-dark:#79B8FF\">SMCKeyData_t</span><span style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\">, bytes));</span></span>\n<span class=\"line\"><span style=\"--shiki-light:#D73A49;--shiki-dark:#F97583\">  return</span><span style=\"--shiki-light:#005CC5;--shiki-dark:#79B8FF\"> 0</span><span style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\">;</span></span>\n<span class=\"line\"><span style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\">}</span></span></code></pre></figure><figure class=\"code\" data-lang=\"bash\"><figcaption><span class=\"lang\">Shell</span></figcaption><pre class=\"shiki shiki-themes github-light github-dark\" style=\"--shiki-light:#24292e;--shiki-dark:#e1e4e8;--shiki-light-bg:#fff;--shiki-dark-bg:#24292e\" tabindex=\"0\"><code><span class=\"line\"><span style=\"--shiki-light:#6F42C1;--shiki-dark:#B392F0\">clang</span><span style=\"--shiki-light:#032F62;--shiki-dark:#9ECBFF\"> size.c</span><span style=\"--shiki-light:#005CC5;--shiki-dark:#79B8FF\"> -o</span><span style=\"--shiki-light:#032F62;--shiki-dark:#9ECBFF\"> size</span><span style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\"> &#x26;&#x26; </span><span style=\"--shiki-light:#6F42C1;--shiki-dark:#B392F0\">./size</span></span></code></pre></figure><p>That prints 80, 12, 28, 40, 44 and 48. On the Swift side, <code>MemoryLayout&lt;KeyData&gt;.offset(of: \\.bytes)</code> gives you the same kind of number for any stored property, so you can line the two lists up field by field.</p>\n<h2 id=\"mirroring-any-c-struct-in-swift\" data-level=\"3\">Mirroring Any C Struct In Swift</h2>\n<p>The best option is not to mirror it at all. If you can put the C declaration in a header, Swift imports the struct with C’s layout. In an app target that’s the bridging header (<code>SWIFT_OBJC_BRIDGING_HEADER</code>); in a package or a plain <code>swiftc</code> build, a module map works:</p>\n<figure class=\"code\" data-lang=\"text\"><figcaption><span class=\"file\">SMCShim/module.modulemap</span></figcaption><pre class=\"shiki shiki-themes github-light github-dark\" style=\"--shiki-light:#24292e;--shiki-dark:#e1e4e8;--shiki-light-bg:#fff;--shiki-dark-bg:#24292e\" tabindex=\"0\"><code><span class=\"line\"><span>module SMCShim {</span></span>\n<span class=\"line\"><span>    header \"smc.h\"</span></span>\n<span class=\"line\"><span>    export *</span></span>\n<span class=\"line\"><span>}</span></span></code></pre></figure><p>After <code>import SMCShim</code>, <code>MemoryLayout&lt;SMCKeyData_t&gt;.size</code> is 80 and you get named fields like <code>data.keyInfo.dataSize</code> for free. The trade is that <code>char</code> fields import as <code>Int8</code> and the 32-byte array imports as a 32-element tuple of <code>Int8</code>.</p>\n<p>If you do write the struct in Swift, avoid tuples and nested Swift structs for any C member that has tail padding, spell those fields out, and add the padding bytes yourself. Then make the layout prove itself. A few preconditions at startup or in a unit test turn a silent <code>kIOReturnBadArgument</code> into a crash that names the problem:</p>\n<figure class=\"code\" data-lang=\"swift\"><figcaption><span class=\"lang\">Swift</span></figcaption><pre class=\"shiki shiki-themes github-light github-dark\" style=\"--shiki-light:#24292e;--shiki-dark:#e1e4e8;--shiki-light-bg:#fff;--shiki-dark-bg:#24292e\" tabindex=\"0\"><code><span class=\"line\"><span style=\"--shiki-light:#005CC5;--shiki-dark:#79B8FF\">precondition</span><span style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\">(</span><span style=\"--shiki-light:#005CC5;--shiki-dark:#79B8FF\">MemoryLayout</span><span style=\"--shiki-light:#D73A49;--shiki-dark:#F97583\">&#x3C;</span><span style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\">KeyData</span><span style=\"--shiki-light:#D73A49;--shiki-dark:#F97583\">></span><span style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\">.</span><span style=\"--shiki-light:#005CC5;--shiki-dark:#79B8FF\">stride</span><span style=\"--shiki-light:#D73A49;--shiki-dark:#F97583\"> ==</span><span style=\"--shiki-light:#005CC5;--shiki-dark:#79B8FF\"> 80</span><span style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\">, </span><span style=\"--shiki-light:#032F62;--shiki-dark:#9ECBFF\">\"KeyData is </span><span style=\"--shiki-light:#032F62;--shiki-dark:#9ECBFF\">\\(</span><span style=\"--shiki-light:#005CC5;--shiki-dark:#79B8FF\">MemoryLayout</span><span style=\"--shiki-light:#D73A49;--shiki-dark:#F97583\">&#x3C;</span><span style=\"--shiki-light:#032F62;--shiki-dark:#9ECBFF\">KeyData</span><span style=\"--shiki-light:#D73A49;--shiki-dark:#F97583\">></span><span style=\"--shiki-light:#032F62;--shiki-dark:#9ECBFF\">.</span><span style=\"--shiki-light:#005CC5;--shiki-dark:#79B8FF\">stride</span><span style=\"--shiki-light:#032F62;--shiki-dark:#9ECBFF\">)</span><span style=\"--shiki-light:#032F62;--shiki-dark:#9ECBFF\"> bytes, SMCKeyData_t is 80\"</span><span style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\">)</span></span>\n<span class=\"line\"><span style=\"--shiki-light:#005CC5;--shiki-dark:#79B8FF\">precondition</span><span style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\">(</span><span style=\"--shiki-light:#005CC5;--shiki-dark:#79B8FF\">MemoryLayout</span><span style=\"--shiki-light:#D73A49;--shiki-dark:#F97583\">&#x3C;</span><span style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\">KeyData</span><span style=\"--shiki-light:#D73A49;--shiki-dark:#F97583\">></span><span style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\">.</span><span style=\"--shiki-light:#005CC5;--shiki-dark:#79B8FF\">offset</span><span style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\">(</span><span style=\"--shiki-light:#005CC5;--shiki-dark:#79B8FF\">of</span><span style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\">: \\.result) </span><span style=\"--shiki-light:#D73A49;--shiki-dark:#F97583\">==</span><span style=\"--shiki-light:#005CC5;--shiki-dark:#79B8FF\"> 40</span><span style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\">)</span></span>\n<span class=\"line\"><span style=\"--shiki-light:#005CC5;--shiki-dark:#79B8FF\">precondition</span><span style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\">(</span><span style=\"--shiki-light:#005CC5;--shiki-dark:#79B8FF\">MemoryLayout</span><span style=\"--shiki-light:#D73A49;--shiki-dark:#F97583\">&#x3C;</span><span style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\">KeyData</span><span style=\"--shiki-light:#D73A49;--shiki-dark:#F97583\">></span><span style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\">.</span><span style=\"--shiki-light:#005CC5;--shiki-dark:#79B8FF\">offset</span><span style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\">(</span><span style=\"--shiki-light:#005CC5;--shiki-dark:#79B8FF\">of</span><span style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\">: \\.bytes) </span><span style=\"--shiki-light:#D73A49;--shiki-dark:#F97583\">==</span><span style=\"--shiki-light:#005CC5;--shiki-dark:#79B8FF\"> 48</span><span style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8\">)</span></span></code></pre></figure><p>Compare <code>stride</code> with <code>sizeof</code>, since <code>stride</code> is the Swift number that includes tail padding. For <code>KeyData</code> the two Swift numbers are both 80, but they often differ: a Swift struct with a <code>UInt32</code> followed by a <code>UInt8</code> has a <code>size</code> of 5 and a <code>stride</code> of 8, and C’s <code>sizeof</code> for the same two fields is 8. The offset checks catch the other case, where fields shift around but the total happens to stay the same.</p>","created_at":"2026-11-02T14:00:00.000Z","updated_at":"2026-11-02T14:00:00.000Z"}