{
  "@context": "https://schema.org",
  "@id": "https://aggr.aymericbeaumet.com/items/lobste-rs/2026-10-07-c-for-rust-programmers/#webpage",
  "@type": [
    "WebPage",
    "ArchiveComponent"
  ],
  "articleBody": "The very first systems programming language I ever learned was Rust. This is uncommon compared to many other programmers; you're more likely to find someone who learned C or C++ first before coming to Rust. As such, there are plenty of \"Rust for C Programmers\" articles on the internet, but little to no \"C for Rust Programmers\" articles out there.\n\nWell, I'm about to change that! I've been learning C and C++ recently, and *holy cow those languages are quirky*. This blog post is a collection of eyebrow-raising details I learned while teaching myself C. (No C++ today, I'm not ready to dig into that can of worms.) This is not a substitute for a proper C tutorial, you'll need to Google one of those yourself. Rather, it's a list of things to keep in mind when working in the language.\n\nWith the premise set, let's draw the curtain and see what C has to offer!\n\n## Boolean Is Not\\* Built-In\n\nThe original version of C did not have a primitive type for booleans, programs instead used the integers 0 and 1. This was changed in [C99](https://en.wikipedia.org/wiki/C99), which added booleans in the optional [`<stdbool.h>`](https://en.cppreference.com/c/header/stdbool) header [\\[1\\]](https://bd103.dev/blog/2026-10-07-c-for-rust-programmers/#fn-_bool):\n\n```c\n#include <stdbool.h>\n\nint main() {\n    bool yes = true;\n    bool no = false;\n\n    return 0;\n}\n```\n\nEven still, `true` and `false` are not literals or keywords like in other languages. Instead, they are definitions that expand to 1 and 0:\n\n```c\n#define true 1\n#define false 0\n```\n\nThis was changed again in [C23](https://en.wikipedia.org/wiki/C23_\\(C_standard_revision\\))[\\[2\\]](https://bd103.dev/blog/2026-10-07-c-for-rust-programmers/#fn-c23), so now booleans are true language primitives, but if you're compiling for earlier versions you'll need to include `<stdbool.h>`.\n\n## Null-Terminated Strings\n\nA Rust [`&str`](https://doc.rust-lang.org/stable/std/primitive.str.html) is 16 bytes: 8 bytes for the memory address and 8 bytes for the string length. This is because `str` is a dynamically sized type, and uses [pointer metadata](https://bd103.dev/blog/2023-08-06-ptr-metadata/) to track the length of the string.\n\n```rust\n// While a normal reference uses only 8 bytes...\nassert_eq!(std::mem::size_of::<&u8>(), 8);\n\n// ...strings use 16 bytes.\nassert_eq!(std::mem::size_of::<&str>(), 16);\n```\n\nThis approach makes fetching the string length extremely efficient, but requires more memory per `&str` reference. C uses a different approach: it doesn't store the size of its strings separately, but instead terminates every single string with a null byte (`\\0`). This is an intentional trade off that results in a few things:\n\n- C programs don't need to keep track of an extra `size` variable alongside the string\n- Every single string needs room at the end for a null byte\n  - This means empty strings `\"\"` still take up one byte of memory!\n- Null bytes cannot easily be used in the middle of a string without messing up [`<string.h>`](https://cppreference.com/c/header/string)'s functions\n- Forgetting the null terminator can result in out-of-bound reads\n\nIn practice, this requires you to remember to allocate extra space for the null terminator and insert it at the end of strings. For example, here is a program that reverses a string in C:\n\n```c\n 1char* reverse(char* forward) {\n 2    // Calculate the string's length, excluding the null terminator.\n 3    unsigned long len = strlen(forward);\n 4    // Allocate enough room for the string and its null terminator.\n 5    char* reversed = malloc(len + 1);\n 6\n 7    for (int i = 0; i < len; i++) {\n 8        reversed[i] = forward[len - 1 - i];\n 9    }\n10\n11    // Add the null terminator at the end.\n12    reversed[len] = '\\0';\n13\n14    return reversed;\n15}\n```\n\nNote lines 5 and 12, which take special measure to account for the null terminator. For reference, the corresponding Rust function [\\[4\\]](https://bd103.dev/blog/2026-10-07-c-for-rust-programmers/#fn-rust-reverse-string) doesn't need to do so:\n\n```rust\nfn reverse(forward: &[u8]) -> Box<[u8]> {\n    let len = forward.len();\n    let mut reversed = Box::<[u8]>::new_uninit_slice(len);\n\n    for i in 0..len {\n        reversed[i].write(forward[len - 1 - i]);\n    }\n\n    unsafe { reversed.assume_init() }\n}\n```\n\n## Target-Dependent Integer Widths\n\nC's integer types are not guaranteed to use an exact number of bits, instead the width varies depending on the target platform.\n\n| Type        | C Standard       | 64-bit Unix | 64-bit Windows |\n| ----------- | ---------------- | ----------- | -------------- |\n| `char`      | at least 8 bits  | 8 bits      | 8 bits         |\n| `short`     | at least 16 bits | 16 bits     | 16 bits        |\n| `int`       | at least 16 bits | 32 bits     | 32 bits        |\n| `long`      | at least 32 bits | 64 bits     | 32 bits        |\n| `long long` | at least 64 bits | 64 bits     | 64 bits        |\n\nData sourced [via cppreference.com](https://cppreference.com/c/language/arithmetic_types)\n\n`long` being 64 bits on Unix and 32 bits on Windows particularly irks me. I recommend following the advice that [a friend of mine](https://github.com/magicalbat) gave me a few years ago: if you care about cross-platform compatibility, only use the fixed width integers provided by [`<stdint.h>`](https://cppreference.com/c/header/stdint):\n\n| Rust    | C                                                                                                      |\n| ------- | ------------------------------------------------------------------------------------------------------ |\n| `u8`    | `uint8_t`                                                                                              |\n| `u16`   | `uint16_t`                                                                                             |\n| `u32`   | `uint32_t`                                                                                             |\n| `u64`   | `uint64_t`                                                                                             |\n| `usize` | `size_t`[\\[5\\]](https://bd103.dev/blog/2026-10-07-c-for-rust-programmers/#fn-size_t-and-ptrdiff_t)    |\n| `i8`    | `int8_t`                                                                                               |\n| `i16`   | `int16_t`                                                                                              |\n| `i32`   | `int32_t`                                                                                              |\n| `i64`   | `int64_t`                                                                                              |\n| `isize` | `ptrdiff_t`[\\[5\\]](https://bd103.dev/blog/2026-10-07-c-for-rust-programmers/#fn-size_t-and-ptrdiff_t) |\n\n## Error Handling Sucks\n\nI really love Rust's error handling. [`Result`](https://doc.rust-lang.org/stable/std/result/enum.Result.html) forces you to address errors, and sum types (`enum`s) and `match` statements make doing so really easy!\n\nC's error handling story, in comparison, is straight up tragic. It seems to boil down to functions returning a \"magic integer\" like -1 or a null pointer to signal there was an error. You can get a little bit more information by reading [`errno`](https://cppreference.com/c/error/errno), a thread-local integer that can be used to check for specific kinds of errors, but in terms of getting actual error messages and stack traces it is much harder.\n\nWhen writing C, one of the biggest things you'll notice is that the language will never force you to handle errors. It's up to you to remember that functions can fail. For example, here's a snippet of code from [Null-Terminated Strings](https://bd103.dev/blog/2026-10-07-c-for-rust-programmers/#null-terminated-strings):\n\n```c\n// Allocate enough room for the string and its null terminator.\nchar* reversed = malloc(len + 1);\n\nfor (int i = 0; i < len; i++) {\n    reversed[i] = forward[len - 1 - i];\n}\n```\n\nTo new programmers, it's not immediately obvious that [`malloc()`](https://cppreference.com/c/memory/malloc) can fail and return a null pointer. If your machine runs out of memory, `reversed[i]` will cause a segfault upon being accessed. In order to avoid unhelpful segfaults, the program should check for a null pointer and gracefully exit if one is found:\n\n```c\nchar* reversed = malloc(len + 1);\n\nif (reversed == NULL) {\n    perror(\"Error\");\n    exit(1);\n}\n```\n\nDoing so provides a much better experience than a segfault, or worse, other unintentional behavior:\n\n```shellscript\n$ ./main\nError: Cannot allocate memory\n```\n\nOf course, remembering to check every single allocated pointer isn't an amazing developer experience. An approach I played around with was recreating Rust's `Result` in C using tagged unions:\n\n```c\nstruct MallocResult {\n    enum Tag { OK, ERROR } tag;\n    union Value {\n        void* ptr;\n        char* error_message;\n    } value;\n};\n```\n\nIt's a complete mess to use, however, and there's *still* nothing stopping you from immediately accessing `result.value.ptr` without handling the error first. The lack of visibility modifiers like `private` and `public`, which could be used to prevent this, appear to be an intentional design decision. C places full trust in the programmer to *do things right™* and gives few facilities for contracts or safe abstractions.\n\nI personally disagree with this approach. I'm not some mastermind programming wizard who never makes mistakes. I'd much rather encode program requirements into the type system so that the compiler can check them for me\\![\\[6\\]](https://bd103.dev/blog/2026-10-07-c-for-rust-programmers/#fn-fearless-simd) That way, I can be reasonably certain that if the code compiles it was written correctly. But I digress.\n\n## Field Access Syntax\n\nC has two different field access operators: [`.`](https://cppreference.com/c/language/operator_member_access#Member_access) for values and [`->`](https://cppreference.com/c/language/operator_member_access#Member_access_through_pointer) for pointers.\n\n```c\nstruct Foo {\n    int field;\n};\n\nstruct Foo value = { 103 };\nstruct Foo* ptr = &value;\n\n// Accessing the field directly.\nprintf(\"%d\\n\", value.field);\n\n// Accessing the field through a pointer.\nprintf(\"%d\\n\", ptr->field);\n```\n\nThis caught me off guard at first, as Rust uses `.` for everything.\n\n![An old lady holding Frank's Red Hot sauce, except Ferris the crab is photoshopped on top saying 'I put that . on everything'](https://bd103.dev/blog/2026-10-07-c-for-rust-programmers/i-put-that-dot-on-everything.jpg)\n\nIf your curious, [this Stack Overflow write up](https://stackoverflow.com/a/13366168) provides some interesting history on why the `->` operator exists.[\\[7\\]](https://bd103.dev/blog/2026-10-07-c-for-rust-programmers/#fn-cursed-arrow-operator)\n\n## Arrays Become Pointers for Fun\n\nArrays have some weird nuance to them. Sometimes they are plain values with their length accessible using [`sizeof()`](https://cppreference.com/c/language/sizeof), other times they are pointers with an unknown size. In general, this is determined by whether you are handling the array within the function it was defined or not.\n\nTo showcase what I mean, here's a very simple C program that prints the size of two arrays:\n\n```c\nchar declared_size[3] = { 1, 2, 3 };\nchar inferred_size[] = { 4, 5, 6 };\n\nprintf(\"Declared size (main): %ld bytes\\n\", sizeof(declared_size));\nprintf(\"Inferred size (main): %ld bytes\\n\", sizeof(inferred_size));\n```\n\nWhen run, this programs tells you that both arrays take 3 bytes of memory. Good!\n\n```shellscript\n$ ./main\nDeclared size (main): 3 bytes\nInferred size (main): 3 bytes\n```\n\nNow, let's make a slight modification. Let's pass `declared_size` and `inferred_size` through a function before printing its size:\n\n```c\nvoid function(char declared_size[3], char inferred_size[]) {\n    printf(\"Declared size (function): %ld bytes\\n\", sizeof(declared_size));\n    printf(\"Inferred size (function): %ld bytes\\n\", sizeof(inferred_size));\n}\n```\n\nNone of the logic changed, the arrays are identical to the previous example, however now the program reports each array takes **8 bytes of memory**:\n\n```shellscript\n$ ./main\nDeclared size (function): 8 bytes\nInferred size (function): 8 bytes\n```\n\nWhy? Because any array passed through a function is *implicitly converted* to a pointer to the first element. From the C compiler's perspective, the above function actually had the following type signature:\n\n```c\nvoid function(char* declared_size, char* inferred_size);\n```\n\nThis is why it confusingly looked like each array was 8 bytes long. The arrays themselves are 3 bytes, but the pointers take up 8 bytes of memory! Handily, Clang raises a warning when you run `sizeof()` on the pointer form of an array, making it easier to catch this mistake:\n\n```shellscript\n$ clang main.c\n06-arrays/main.c:5:59: warning: sizeof on array function parameter will return size of 'char *'\n      instead of 'char[3]' [-Wsizeof-array-argument]\n    5 |     printf(\"Declared size (function): %ld bytes\\n\", sizeof(declared_size));\n      |                                                           ^\n06-arrays/main.c:4:20: note: declared here\n    4 | void function(char declared_size[3], char inferred_size[]) {\n      |                    ^\n06-arrays/main.c:6:59: warning: sizeof on array function parameter will return size of 'char *'\n      instead of 'char[]' [-Wsizeof-array-argument]\n    6 |     printf(\"Inferred size (function): %ld bytes\\n\", sizeof(inferred_size));\n      |                                                           ^\n06-arrays/main.c:4:43: note: declared here\n    4 | void function(char declared_size[3], char inferred_size[]) {\n      |                                           ^\n2 warnings generated.\n```\n\n## Oh Yeah References Don't Exist\n\nI'd be remiss if I didn't mention it once. C has no borrow checking, and no concept of references. It's all [raw pointers](https://doc.rust-lang.org/stable/std/primitive.pointer.html). This means you can do fun pointer arithmetic like so:\n\n```c\nint array[] = { 0, 1, 2, 3, 4, 5 };\n\n// Woah, iterating over pointers instead of indexes!\nfor (int* x = &array[0]; x < &array[6]; x++) {\n    *x = 5 - *x;\n}\n```\n\nHowever, I'm not sure how good an idea that is. 😅\n\nEither way, be careful when you mess with pointers. Making mistakes with memory results in buffer overflows and out-of-bounds writes, which provide significant threats to the security of your code.\n\n![A graph visualizing which vulnerability category had the most CVEs between November 2021 and January 2022. Buffer overflow is the third most common, with 346 CVEs, and out-of-bounds writes are the ninth most common, with 204 CVEs. The two categories more common than buffer overflow are denial-of-service with 488 and cross-site scripting with 683.](https://bd103.dev/blog/2026-10-07-c-for-rust-programmers/vuln-categories-2021.png)\n\nVulnerability category distribution for CVEs registered between Nov. 2021 and Jan. 2022, [via](https://unit42.paloaltonetworks.com/network-security-trends-cross-site-scripting/)\n\n## Conclusion\n\nI hope you enjoyed this article! I've honestly had a lot of fun learning C. And while I doubt I'll reach for it for personal projects, it's absolutely a crucial language to know as a systems programmer. All the examples in this blog are [available on Github](https://github.com/BD103/C-for-Rust-Programmers), if you'd like to mess with them yourself!\n\nUntil next time,\n\n\\- BD103 :)\n\n1. Technically you can use [`_Bool`](https://en.cppreference.com/c/keyword/_Bool) without the header, but you still need it for the `true` and `false` definitions. [↩](https://bd103.dev/blog/2026-10-07-c-for-rust-programmers/#fr-_bool-1)\n\n2. It looks like [Clang still has only partial support for C23](https://clang.llvm.org/c_status.html), so you may need to wait a little while longer before chucking away your `#include <stdbool.h>` statements. [↩](https://bd103.dev/blog/2026-10-07-c-for-rust-programmers/#fr-c23-1)\n\n3. The corresponding Rust function is not idiomatic, and can only correctly handle ASCII text. If I were writing a production version of this function, it would be a single line of code: `forward.chars().rev().collect::<String>()`. [↩](https://bd103.dev/blog/2026-10-07-c-for-rust-programmers/#fr-rust-reverse-string-1)\n\n4. [`usize`](https://doc.rust-lang.org/stable/std/primitive.usize.html) and [`isize`](https://doc.rust-lang.org/stable/std/primitive.isize.html) don't perfectly map semantically to [`size_t`](https://cppreference.com/c/types/size_t) and [`ptrdiff_t`](https://cppreference.com/c/types/ptrdiff_t). I don't fully understand the difference, however, so I recommend doing your own research before using these types. [↩](https://bd103.dev/blog/2026-10-07-c-for-rust-programmers/#fr-size_t-and-ptrdiff_t-1) [↩2](https://bd103.dev/blog/2026-10-07-c-for-rust-programmers/#fr-size_t-and-ptrdiff_t-2)\n\n5. [This blog post on Fearless SIMD](https://shnatsel.github.io/safe-simd-in-rust-even-on-the-inside/) provides a great example of using Rust's type system to guarantee the correctness of code. I highly recommend giving it a read! [↩](https://bd103.dev/blog/2026-10-07-c-for-rust-programmers/#fr-fearless-simd-1)\n\n6. My favorite line of code from that post is `100->a = 0;`, it's so cursed! [↩](https://bd103.dev/blog/2026-10-07-c-for-rust-programmers/#fr-cursed-arrow-operator-1)\n",
  "authors": [
    "bd103.dev by BD103"
  ],
  "captured_at": "2026-10-09T05:58:27.034165253+00:00",
  "category": "news",
  "content_html": "<p>The very first systems programming language I ever learned was Rust. This is uncommon compared to many other programmers; you're more likely to find someone who learned C or C++ first before coming to Rust. As such, there are plenty of &quot;Rust for C Programmers&quot; articles on the internet, but little to no &quot;C for Rust Programmers&quot; articles out there.</p>\n<p>Well, I'm about to change that! I've been learning C and C++ recently, and <em>holy cow those languages are quirky</em>. This blog post is a collection of eyebrow-raising details I learned while teaching myself C. (No C++ today, I'm not ready to dig into that can of worms.) This is not a substitute for a proper C tutorial, you'll need to Google one of those yourself. Rather, it's a list of things to keep in mind when working in the language.</p>\n<p>With the premise set, let's draw the curtain and see what C has to offer!</p>\n<h2>Boolean Is Not* Built-In</h2>\n<p>The original version of C did not have a primitive type for booleans, programs instead used the integers 0 and 1. This was changed in <a target=\"_blank\" rel=\"noopener noreferrer\" href=\"https://en.wikipedia.org/wiki/C99\">C99</a>, which added booleans in the optional <a target=\"_blank\" rel=\"noopener noreferrer\" href=\"https://en.cppreference.com/c/header/stdbool\"><code>&lt;stdbool.h&gt;</code></a> header <sup class=\"citation-ref\"><a target=\"_blank\" rel=\"noopener noreferrer\" href=\"https://bd103.dev/blog/2026-10-07-c-for-rust-programmers/#fn-_bool\">[1]</a></sup>:</p>\n<pre><code class=\"language-c\"><span class=\"code-snippet\" data-language=\"C\"><span class=\"syntax-source syntax-c\"><span class=\"syntax-meta syntax-preprocessor syntax-include syntax-c\"><span class=\"syntax-keyword syntax-control syntax-import syntax-include syntax-c\">#include</span> <span class=\"syntax-string syntax-quoted syntax-other syntax-lt-gt syntax-include syntax-c\"><span class=\"syntax-punctuation syntax-definition syntax-string syntax-begin syntax-c\">&lt;</span>stdbool.h<span class=\"syntax-punctuation syntax-definition syntax-string syntax-end syntax-c\">&gt;</span></span>\n</span>\n<span class=\"syntax-storage syntax-type syntax-c\">int</span> <span class=\"syntax-meta syntax-function syntax-c\"><span class=\"syntax-entity syntax-name syntax-function syntax-c\">main</span></span><span class=\"syntax-meta syntax-function syntax-parameters syntax-c\"><span class=\"syntax-meta syntax-group syntax-c\"><span class=\"syntax-punctuation syntax-section syntax-group syntax-begin syntax-c\">(</span></span></span><span class=\"syntax-meta syntax-function syntax-parameters syntax-c\"><span class=\"syntax-meta syntax-group syntax-c\"><span class=\"syntax-punctuation syntax-section syntax-group syntax-end syntax-c\">)</span></span></span><span class=\"syntax-meta syntax-function syntax-c\"> </span><span class=\"syntax-meta syntax-function syntax-c\"><span class=\"syntax-meta syntax-block syntax-c\"><span class=\"syntax-punctuation syntax-section syntax-block syntax-begin syntax-c\">{</span></span></span><span class=\"syntax-meta syntax-function syntax-c\"><span class=\"syntax-meta syntax-block syntax-c\">\n    <span class=\"syntax-storage syntax-type syntax-c\">bool</span> yes <span class=\"syntax-keyword syntax-operator syntax-assignment syntax-c\">=</span> <span class=\"syntax-constant syntax-language syntax-c\">true</span><span class=\"syntax-punctuation syntax-terminator syntax-c\">;</span>\n    <span class=\"syntax-storage syntax-type syntax-c\">bool</span> no <span class=\"syntax-keyword syntax-operator syntax-assignment syntax-c\">=</span> <span class=\"syntax-constant syntax-language syntax-c\">false</span><span class=\"syntax-punctuation syntax-terminator syntax-c\">;</span>\n\n    <span class=\"syntax-keyword syntax-control syntax-c\">return</span> <span class=\"syntax-constant syntax-numeric syntax-c\">0</span><span class=\"syntax-punctuation syntax-terminator syntax-c\">;</span>\n</span></span><span class=\"syntax-meta syntax-function syntax-c\"><span class=\"syntax-meta syntax-block syntax-c\"><span class=\"syntax-punctuation syntax-section syntax-block syntax-end syntax-c\">}</span></span></span>\n</span></span></code></pre>\n<p>Even still, <code>true</code> and <code>false</code> are not literals or keywords like in other languages. Instead, they are definitions that expand to 1 and 0:</p>\n<pre><code class=\"language-c\"><span class=\"code-snippet\" data-language=\"C\"><span class=\"syntax-source syntax-c\"><span class=\"syntax-meta syntax-preprocessor syntax-macro syntax-c\"><span class=\"syntax-keyword syntax-control syntax-import syntax-define syntax-c\">#define</span></span><span class=\"syntax-meta syntax-preprocessor syntax-macro syntax-c\"> <span class=\"syntax-entity syntax-name syntax-constant syntax-preprocessor syntax-c\">true</span></span><span class=\"syntax-meta syntax-preprocessor syntax-macro syntax-c\"> <span class=\"syntax-constant syntax-numeric syntax-c\">1</span></span>\n<span class=\"syntax-meta syntax-preprocessor syntax-macro syntax-c\"><span class=\"syntax-keyword syntax-control syntax-import syntax-define syntax-c\">#define</span></span><span class=\"syntax-meta syntax-preprocessor syntax-macro syntax-c\"> <span class=\"syntax-entity syntax-name syntax-constant syntax-preprocessor syntax-c\">false</span></span><span class=\"syntax-meta syntax-preprocessor syntax-macro syntax-c\"> <span class=\"syntax-constant syntax-numeric syntax-c\">0</span></span>\n</span></span></code></pre>\n<p>This was changed again in <a target=\"_blank\" rel=\"noopener noreferrer\" href=\"https://en.wikipedia.org/wiki/C23_(C_standard_revision)\">C23</a><sup class=\"citation-ref\"><a target=\"_blank\" rel=\"noopener noreferrer\" href=\"https://bd103.dev/blog/2026-10-07-c-for-rust-programmers/#fn-c23\">[2]</a></sup>, so now booleans are true language primitives, but if you're compiling for earlier versions you'll need to include <code>&lt;stdbool.h&gt;</code>.</p>\n<h2>Null-Terminated Strings</h2>\n<p>A Rust <a target=\"_blank\" rel=\"noopener noreferrer\" href=\"https://doc.rust-lang.org/stable/std/primitive.str.html\"><code>&amp;str</code></a> is 16 bytes: 8 bytes for the memory address and 8 bytes for the string length. This is because <code>str</code> is a dynamically sized type, and uses <a target=\"_blank\" rel=\"noopener noreferrer\" href=\"https://bd103.dev/blog/2023-08-06-ptr-metadata/\">pointer metadata</a> to track the length of the string.</p>\n<pre><code class=\"language-rust\"><span class=\"code-snippet\" data-language=\"Rust\"><span class=\"syntax-source syntax-rust\"><span class=\"syntax-comment syntax-line syntax-double-slash syntax-rust\"><span class=\"syntax-punctuation syntax-definition syntax-comment syntax-rust\">//</span> While a normal reference uses only 8 bytes...\n</span><span class=\"syntax-support syntax-macro syntax-rust\">assert_eq!</span><span class=\"syntax-meta syntax-group syntax-rust\"><span class=\"syntax-punctuation syntax-section syntax-group syntax-begin syntax-rust\">(</span><span class=\"syntax-meta syntax-path syntax-rust\">std<span class=\"syntax-punctuation syntax-accessor syntax-rust\">::</span></span><span class=\"syntax-meta syntax-path syntax-rust\">mem<span class=\"syntax-punctuation syntax-accessor syntax-rust\">::</span></span><span class=\"syntax-meta syntax-path syntax-rust\">size_of<span class=\"syntax-punctuation syntax-accessor syntax-rust\">::</span></span><span class=\"syntax-meta syntax-generic syntax-rust\"><span class=\"syntax-punctuation syntax-definition syntax-generic syntax-begin syntax-rust\">&lt;</span><span class=\"syntax-keyword syntax-operator syntax-rust\">&amp;</span><span class=\"syntax-storage syntax-type syntax-rust\">u8</span><span class=\"syntax-punctuation syntax-definition syntax-generic syntax-end syntax-rust\">&gt;</span></span><span class=\"syntax-meta syntax-group syntax-rust\"><span class=\"syntax-punctuation syntax-section syntax-group syntax-begin syntax-rust\">(</span></span><span class=\"syntax-meta syntax-group syntax-rust\"><span class=\"syntax-punctuation syntax-section syntax-group syntax-end syntax-rust\">)</span></span><span class=\"syntax-punctuation syntax-separator syntax-rust\">,</span> <span class=\"syntax-constant syntax-numeric syntax-integer syntax-decimal syntax-rust\">8</span></span><span class=\"syntax-meta syntax-group syntax-rust\"><span class=\"syntax-punctuation syntax-section syntax-group syntax-end syntax-rust\">)</span></span><span class=\"syntax-punctuation syntax-terminator syntax-rust\">;</span>\n\n<span class=\"syntax-comment syntax-line syntax-double-slash syntax-rust\"><span class=\"syntax-punctuation syntax-definition syntax-comment syntax-rust\">//</span> ...strings use 16 bytes.\n</span><span class=\"syntax-support syntax-macro syntax-rust\">assert_eq!</span><span class=\"syntax-meta syntax-group syntax-rust\"><span class=\"syntax-punctuation syntax-section syntax-group syntax-begin syntax-rust\">(</span><span class=\"syntax-meta syntax-path syntax-rust\">std<span class=\"syntax-punctuation syntax-accessor syntax-rust\">::</span></span><span class=\"syntax-meta syntax-path syntax-rust\">mem<span class=\"syntax-punctuation syntax-accessor syntax-rust\">::</span></span><span class=\"syntax-meta syntax-path syntax-rust\">size_of<span class=\"syntax-punctuation syntax-accessor syntax-rust\">::</span></span><span class=\"syntax-meta syntax-generic syntax-rust\"><span class=\"syntax-punctuation syntax-definition syntax-generic syntax-begin syntax-rust\">&lt;</span><span class=\"syntax-keyword syntax-operator syntax-rust\">&amp;</span><span class=\"syntax-storage syntax-type syntax-rust\">str</span><span class=\"syntax-punctuation syntax-definition syntax-generic syntax-end syntax-rust\">&gt;</span></span><span class=\"syntax-meta syntax-group syntax-rust\"><span class=\"syntax-punctuation syntax-section syntax-group syntax-begin syntax-rust\">(</span></span><span class=\"syntax-meta syntax-group syntax-rust\"><span class=\"syntax-punctuation syntax-section syntax-group syntax-end syntax-rust\">)</span></span><span class=\"syntax-punctuation syntax-separator syntax-rust\">,</span> <span class=\"syntax-constant syntax-numeric syntax-integer syntax-decimal syntax-rust\">16</span></span><span class=\"syntax-meta syntax-group syntax-rust\"><span class=\"syntax-punctuation syntax-section syntax-group syntax-end syntax-rust\">)</span></span><span class=\"syntax-punctuation syntax-terminator syntax-rust\">;</span>\n</span></span></code></pre>\n<p>This approach makes fetching the string length extremely efficient, but requires more memory per <code>&amp;str</code> reference. C uses a different approach: it doesn't store the size of its strings separately, but instead terminates every single string with a null byte (<code>\\0</code>). This is an intentional trade off that results in a few things:</p>\n<ul>\n<li>C programs don't need to keep track of an extra <code>size</code> variable alongside the string</li>\n<li>Every single string needs room at the end for a null byte\n<ul>\n<li>This means empty strings <code>&quot;&quot;</code> still take up one byte of memory!</li>\n</ul>\n</li>\n<li>Null bytes cannot easily be used in the middle of a string without messing up <a target=\"_blank\" rel=\"noopener noreferrer\" href=\"https://cppreference.com/c/header/string\"><code>&lt;string.h&gt;</code></a>'s functions</li>\n<li>Forgetting the null terminator can result in out-of-bound reads</li>\n</ul>\n<p>In practice, this requires you to remember to allocate extra space for the null terminator and insert it at the end of strings. For example, here is a program that reverses a string in C:</p>\n<pre><code class=\"language-c\"><span class=\"code-snippet\" data-language=\"C\"><span class=\"syntax-source syntax-c\"> 1char<span class=\"syntax-keyword syntax-operator syntax-c\">*</span> <span class=\"syntax-meta syntax-function syntax-c\"><span class=\"syntax-entity syntax-name syntax-function syntax-c\">reverse</span></span><span class=\"syntax-meta syntax-function syntax-parameters syntax-c\"><span class=\"syntax-meta syntax-group syntax-c\"><span class=\"syntax-punctuation syntax-section syntax-group syntax-begin syntax-c\">(</span></span></span><span class=\"syntax-meta syntax-function syntax-parameters syntax-c\"><span class=\"syntax-meta syntax-group syntax-c\"><span class=\"syntax-storage syntax-type syntax-c\">char</span><span class=\"syntax-keyword syntax-operator syntax-c\">*</span> <span class=\"syntax-variable syntax-parameter syntax-c\">forward</span><span class=\"syntax-punctuation syntax-section syntax-group syntax-end syntax-c\">)</span></span></span><span class=\"syntax-meta syntax-function syntax-c\"> </span><span class=\"syntax-meta syntax-function syntax-c\"><span class=\"syntax-meta syntax-block syntax-c\"><span class=\"syntax-punctuation syntax-section syntax-block syntax-begin syntax-c\">{</span></span></span><span class=\"syntax-meta syntax-function syntax-c\"><span class=\"syntax-meta syntax-block syntax-c\">\n <span class=\"syntax-constant syntax-numeric syntax-c\">2</span>    <span class=\"syntax-comment syntax-line syntax-double-slash syntax-c\"><span class=\"syntax-punctuation syntax-definition syntax-comment syntax-c\">//</span> Calculate the string&#39;s length, excluding the null terminator.\n</span> <span class=\"syntax-constant syntax-numeric syntax-c\">3</span>    <span class=\"syntax-storage syntax-type syntax-c\">unsigned</span> <span class=\"syntax-storage syntax-type syntax-c\">long</span> len <span class=\"syntax-keyword syntax-operator syntax-assignment syntax-c\">=</span> <span class=\"syntax-meta syntax-function-call syntax-c\"><span class=\"syntax-support syntax-function syntax-C99 syntax-c\">strlen</span><span class=\"syntax-meta syntax-group syntax-c\"><span class=\"syntax-punctuation syntax-section syntax-group syntax-begin syntax-c\">(</span></span></span><span class=\"syntax-meta syntax-function-call syntax-c\"><span class=\"syntax-meta syntax-group syntax-c\">forward</span></span><span class=\"syntax-meta syntax-function-call syntax-c\"><span class=\"syntax-meta syntax-group syntax-c\"><span class=\"syntax-punctuation syntax-section syntax-group syntax-end syntax-c\">)</span></span></span><span class=\"syntax-punctuation syntax-terminator syntax-c\">;</span>\n <span class=\"syntax-constant syntax-numeric syntax-c\">4</span>    <span class=\"syntax-comment syntax-line syntax-double-slash syntax-c\"><span class=\"syntax-punctuation syntax-definition syntax-comment syntax-c\">//</span> Allocate enough room for the string and its null terminator.\n</span> <span class=\"syntax-constant syntax-numeric syntax-c\">5</span>    <span class=\"syntax-storage syntax-type syntax-c\">char</span><span class=\"syntax-keyword syntax-operator syntax-c\">*</span> reversed <span class=\"syntax-keyword syntax-operator syntax-assignment syntax-c\">=</span> <span class=\"syntax-meta syntax-function-call syntax-c\"><span class=\"syntax-support syntax-function syntax-C99 syntax-c\">malloc</span><span class=\"syntax-meta syntax-group syntax-c\"><span class=\"syntax-punctuation syntax-section syntax-group syntax-begin syntax-c\">(</span></span></span><span class=\"syntax-meta syntax-function-call syntax-c\"><span class=\"syntax-meta syntax-group syntax-c\">len <span class=\"syntax-keyword syntax-operator syntax-arithmetic syntax-c\">+</span> <span class=\"syntax-constant syntax-numeric syntax-c\">1</span></span></span><span class=\"syntax-meta syntax-function-call syntax-c\"><span class=\"syntax-meta syntax-group syntax-c\"><span class=\"syntax-punctuation syntax-section syntax-group syntax-end syntax-c\">)</span></span></span><span class=\"syntax-punctuation syntax-terminator syntax-c\">;</span>\n <span class=\"syntax-constant syntax-numeric syntax-c\">6</span>\n <span class=\"syntax-constant syntax-numeric syntax-c\">7</span>    <span class=\"syntax-keyword syntax-control syntax-c\">for</span> <span class=\"syntax-meta syntax-group syntax-c\"><span class=\"syntax-punctuation syntax-section syntax-group syntax-begin syntax-c\">(</span><span class=\"syntax-storage syntax-type syntax-c\">int</span> i <span class=\"syntax-keyword syntax-operator syntax-assignment syntax-c\">=</span> <span class=\"syntax-constant syntax-numeric syntax-c\">0</span><span class=\"syntax-punctuation syntax-terminator syntax-c\">;</span> i <span class=\"syntax-keyword syntax-operator syntax-comparison syntax-c\">&lt;</span> len<span class=\"syntax-punctuation syntax-terminator syntax-c\">;</span> i<span class=\"syntax-keyword syntax-operator syntax-arithmetic syntax-c\">+</span><span class=\"syntax-keyword syntax-operator syntax-arithmetic syntax-c\">+</span><span class=\"syntax-punctuation syntax-section syntax-group syntax-end syntax-c\">)</span></span> <span class=\"syntax-meta syntax-block syntax-c\"><span class=\"syntax-punctuation syntax-section syntax-block syntax-begin syntax-c\">{</span>\n <span class=\"syntax-constant syntax-numeric syntax-c\">8</span>        reversed<span class=\"syntax-meta syntax-brackets syntax-c\"><span class=\"syntax-punctuation syntax-section syntax-brackets syntax-begin syntax-c\">[</span>i<span class=\"syntax-punctuation syntax-section syntax-brackets syntax-end syntax-c\">]</span></span> <span class=\"syntax-keyword syntax-operator syntax-assignment syntax-c\">=</span> forward<span class=\"syntax-meta syntax-brackets syntax-c\"><span class=\"syntax-punctuation syntax-section syntax-brackets syntax-begin syntax-c\">[</span>len <span class=\"syntax-keyword syntax-operator syntax-arithmetic syntax-c\">-</span> <span class=\"syntax-constant syntax-numeric syntax-c\">1</span> <span class=\"syntax-keyword syntax-operator syntax-arithmetic syntax-c\">-</span> i<span class=\"syntax-punctuation syntax-section syntax-brackets syntax-end syntax-c\">]</span></span><span class=\"syntax-punctuation syntax-terminator syntax-c\">;</span>\n <span class=\"syntax-constant syntax-numeric syntax-c\">9</span>    <span class=\"syntax-punctuation syntax-section syntax-block syntax-end syntax-c\">}</span></span>\n<span class=\"syntax-constant syntax-numeric syntax-c\">10</span>\n<span class=\"syntax-constant syntax-numeric syntax-c\">11</span>    <span class=\"syntax-comment syntax-line syntax-double-slash syntax-c\"><span class=\"syntax-punctuation syntax-definition syntax-comment syntax-c\">//</span> Add the null terminator at the end.\n</span><span class=\"syntax-constant syntax-numeric syntax-c\">12</span>    reversed<span class=\"syntax-meta syntax-brackets syntax-c\"><span class=\"syntax-punctuation syntax-section syntax-brackets syntax-begin syntax-c\">[</span>len<span class=\"syntax-punctuation syntax-section syntax-brackets syntax-end syntax-c\">]</span></span> <span class=\"syntax-keyword syntax-operator syntax-assignment syntax-c\">=</span> <span class=\"syntax-string syntax-quoted syntax-single syntax-c\"><span class=\"syntax-punctuation syntax-definition syntax-string syntax-begin syntax-c\">&#39;</span><span class=\"syntax-constant syntax-character syntax-escape syntax-c\">\\0</span><span class=\"syntax-punctuation syntax-definition syntax-string syntax-end syntax-c\">&#39;</span></span><span class=\"syntax-punctuation syntax-terminator syntax-c\">;</span>\n<span class=\"syntax-constant syntax-numeric syntax-c\">13</span>\n<span class=\"syntax-constant syntax-numeric syntax-c\">14</span>    <span class=\"syntax-keyword syntax-control syntax-c\">return</span> reversed<span class=\"syntax-punctuation syntax-terminator syntax-c\">;</span>\n<span class=\"syntax-constant syntax-numeric syntax-c\">15</span></span></span><span class=\"syntax-meta syntax-function syntax-c\"><span class=\"syntax-meta syntax-block syntax-c\"><span class=\"syntax-punctuation syntax-section syntax-block syntax-end syntax-c\">}</span></span></span>\n</span></span></code></pre>\n<p>Note lines 5 and 12, which take special measure to account for the null terminator. For reference, the corresponding Rust function <sup class=\"citation-ref\"><a target=\"_blank\" rel=\"noopener noreferrer\" href=\"https://bd103.dev/blog/2026-10-07-c-for-rust-programmers/#fn-rust-reverse-string\">[4]</a></sup> doesn't need to do so:</p>\n<pre><code class=\"language-rust\"><span class=\"code-snippet\" data-language=\"Rust\"><span class=\"syntax-source syntax-rust\"><span class=\"syntax-meta syntax-function syntax-rust\"><span class=\"syntax-meta syntax-function syntax-rust\"><span class=\"syntax-storage syntax-type syntax-function syntax-rust\">fn</span> </span><span class=\"syntax-entity syntax-name syntax-function syntax-rust\">reverse</span></span><span class=\"syntax-meta syntax-function syntax-rust\"><span class=\"syntax-meta syntax-function syntax-parameters syntax-rust\"><span class=\"syntax-punctuation syntax-section syntax-parameters syntax-begin syntax-rust\">(</span><span class=\"syntax-variable syntax-parameter syntax-rust\">forward</span><span class=\"syntax-punctuation syntax-separator syntax-rust\">:</span> <span class=\"syntax-keyword syntax-operator syntax-rust\">&amp;</span>[<span class=\"syntax-storage syntax-type syntax-rust\">u8</span>]</span><span class=\"syntax-meta syntax-function syntax-rust\"><span class=\"syntax-meta syntax-function syntax-parameters syntax-rust\"><span class=\"syntax-punctuation syntax-section syntax-parameters syntax-end syntax-rust\">)</span></span></span></span><span class=\"syntax-meta syntax-function syntax-rust\"> <span class=\"syntax-meta syntax-function syntax-return-type syntax-rust\"><span class=\"syntax-punctuation syntax-separator syntax-rust\">-&gt;</span> <span class=\"syntax-meta syntax-generic syntax-rust\">Box<span class=\"syntax-punctuation syntax-definition syntax-generic syntax-begin syntax-rust\">&lt;</span><span class=\"syntax-meta syntax-group syntax-rust\"><span class=\"syntax-punctuation syntax-section syntax-group syntax-begin syntax-rust\">[</span><span class=\"syntax-storage syntax-type syntax-rust\">u8</span><span class=\"syntax-punctuation syntax-section syntax-group syntax-end syntax-rust\">]</span></span><span class=\"syntax-punctuation syntax-definition syntax-generic syntax-end syntax-rust\">&gt;</span></span></span> </span><span class=\"syntax-meta syntax-function syntax-rust\"><span class=\"syntax-meta syntax-block syntax-rust\"><span class=\"syntax-punctuation syntax-section syntax-block syntax-begin syntax-rust\">{</span>\n    <span class=\"syntax-storage syntax-type syntax-rust\">let</span> len <span class=\"syntax-keyword syntax-operator syntax-rust\">=</span> forward.<span class=\"syntax-support syntax-function syntax-rust\">len</span><span class=\"syntax-meta syntax-group syntax-rust\"><span class=\"syntax-punctuation syntax-section syntax-group syntax-begin syntax-rust\">(</span></span><span class=\"syntax-meta syntax-group syntax-rust\"><span class=\"syntax-punctuation syntax-section syntax-group syntax-end syntax-rust\">)</span></span><span class=\"syntax-punctuation syntax-terminator syntax-rust\">;</span>\n    <span class=\"syntax-storage syntax-type syntax-rust\">let</span> <span class=\"syntax-storage syntax-modifier syntax-rust\">mut</span> reversed <span class=\"syntax-keyword syntax-operator syntax-rust\">=</span> <span class=\"syntax-support syntax-type syntax-rust\">Box</span><span class=\"syntax-punctuation syntax-separator syntax-rust\">:</span><span class=\"syntax-punctuation syntax-separator syntax-rust\">:</span><span class=\"syntax-meta syntax-generic syntax-rust\"><span class=\"syntax-punctuation syntax-definition syntax-generic syntax-begin syntax-rust\">&lt;</span><span class=\"syntax-meta syntax-group syntax-rust\"><span class=\"syntax-punctuation syntax-section syntax-group syntax-begin syntax-rust\">[</span><span class=\"syntax-storage syntax-type syntax-rust\">u8</span><span class=\"syntax-punctuation syntax-section syntax-group syntax-end syntax-rust\">]</span></span><span class=\"syntax-punctuation syntax-definition syntax-generic syntax-end syntax-rust\">&gt;</span></span><span class=\"syntax-meta syntax-path syntax-rust\"><span class=\"syntax-punctuation syntax-accessor syntax-rust\">::</span></span>new_uninit_slice<span class=\"syntax-meta syntax-group syntax-rust\"><span class=\"syntax-punctuation syntax-section syntax-group syntax-begin syntax-rust\">(</span>len</span><span class=\"syntax-meta syntax-group syntax-rust\"><span class=\"syntax-punctuation syntax-section syntax-group syntax-end syntax-rust\">)</span></span><span class=\"syntax-punctuation syntax-terminator syntax-rust\">;</span>\n\n    <span class=\"syntax-keyword syntax-control syntax-rust\">for</span> i <span class=\"syntax-keyword syntax-operator syntax-rust\">in</span> <span class=\"syntax-constant syntax-numeric syntax-integer syntax-decimal syntax-rust\">0</span><span class=\"syntax-keyword syntax-operator syntax-rust\">..</span>len <span class=\"syntax-meta syntax-block syntax-rust\"><span class=\"syntax-punctuation syntax-section syntax-block syntax-begin syntax-rust\">{</span>\n        reversed<span class=\"syntax-meta syntax-group syntax-rust\"><span class=\"syntax-punctuation syntax-section syntax-group syntax-begin syntax-rust\">[</span>i<span class=\"syntax-punctuation syntax-section syntax-group syntax-end syntax-rust\">]</span></span>.<span class=\"syntax-support syntax-function syntax-rust\">write</span><span class=\"syntax-meta syntax-group syntax-rust\"><span class=\"syntax-punctuation syntax-section syntax-group syntax-begin syntax-rust\">(</span>forward<span class=\"syntax-meta syntax-group syntax-rust\"><span class=\"syntax-punctuation syntax-section syntax-group syntax-begin syntax-rust\">[</span>len <span class=\"syntax-keyword syntax-operator syntax-rust\">-</span> <span class=\"syntax-constant syntax-numeric syntax-integer syntax-decimal syntax-rust\">1</span> <span class=\"syntax-keyword syntax-operator syntax-rust\">-</span> i<span class=\"syntax-punctuation syntax-section syntax-group syntax-end syntax-rust\">]</span></span></span><span class=\"syntax-meta syntax-group syntax-rust\"><span class=\"syntax-punctuation syntax-section syntax-group syntax-end syntax-rust\">)</span></span><span class=\"syntax-punctuation syntax-terminator syntax-rust\">;</span>\n    </span><span class=\"syntax-meta syntax-block syntax-rust\"><span class=\"syntax-punctuation syntax-section syntax-block syntax-end syntax-rust\">}</span></span>\n\n    <span class=\"syntax-storage syntax-modifier syntax-rust\">unsafe</span> <span class=\"syntax-meta syntax-block syntax-rust\"><span class=\"syntax-punctuation syntax-section syntax-block syntax-begin syntax-rust\">{</span> reversed.<span class=\"syntax-support syntax-function syntax-rust\">assume_init</span><span class=\"syntax-meta syntax-group syntax-rust\"><span class=\"syntax-punctuation syntax-section syntax-group syntax-begin syntax-rust\">(</span></span><span class=\"syntax-meta syntax-group syntax-rust\"><span class=\"syntax-punctuation syntax-section syntax-group syntax-end syntax-rust\">)</span></span> </span><span class=\"syntax-meta syntax-block syntax-rust\"><span class=\"syntax-punctuation syntax-section syntax-block syntax-end syntax-rust\">}</span></span>\n</span><span class=\"syntax-meta syntax-block syntax-rust\"><span class=\"syntax-punctuation syntax-section syntax-block syntax-end syntax-rust\">}</span></span></span>\n</span></span></code></pre>\n<h2>Target-Dependent Integer Widths</h2>\n<p>C's integer types are not guaranteed to use an exact number of bits, instead the width varies depending on the target platform.</p>\n<table>\n<thead>\n<tr>\n<th>Type</th>\n<th>C Standard</th>\n<th>64-bit Unix</th>\n<th>64-bit Windows</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td><code>char</code></td>\n<td>at least 8 bits</td>\n<td>8 bits</td>\n<td>8 bits</td>\n</tr>\n<tr>\n<td><code>short</code></td>\n<td>at least 16 bits</td>\n<td>16 bits</td>\n<td>16 bits</td>\n</tr>\n<tr>\n<td><code>int</code></td>\n<td>at least 16 bits</td>\n<td>32 bits</td>\n<td>32 bits</td>\n</tr>\n<tr>\n<td><code>long</code></td>\n<td>at least 32 bits</td>\n<td>64 bits</td>\n<td>32 bits</td>\n</tr>\n<tr>\n<td><code>long long</code></td>\n<td>at least 64 bits</td>\n<td>64 bits</td>\n<td>64 bits</td>\n</tr>\n</tbody>\n</table>\n<p>Data sourced <a target=\"_blank\" rel=\"noopener noreferrer\" href=\"https://cppreference.com/c/language/arithmetic_types\">via cppreference.com</a></p>\n<p><code>long</code> being 64 bits on Unix and 32 bits on Windows particularly irks me. I recommend following the advice that <a target=\"_blank\" rel=\"noopener noreferrer\" href=\"https://github.com/magicalbat\">a friend of mine</a> gave me a few years ago: if you care about cross-platform compatibility, only use the fixed width integers provided by <a target=\"_blank\" rel=\"noopener noreferrer\" href=\"https://cppreference.com/c/header/stdint\"><code>&lt;stdint.h&gt;</code></a>:</p>\n<table>\n<thead>\n<tr>\n<th>Rust</th>\n<th>C</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td><code>u8</code></td>\n<td><code>uint8_t</code></td>\n</tr>\n<tr>\n<td><code>u16</code></td>\n<td><code>uint16_t</code></td>\n</tr>\n<tr>\n<td><code>u32</code></td>\n<td><code>uint32_t</code></td>\n</tr>\n<tr>\n<td><code>u64</code></td>\n<td><code>uint64_t</code></td>\n</tr>\n<tr>\n<td><code>usize</code></td>\n<td><code>size_t</code><sup class=\"citation-ref\"><a target=\"_blank\" rel=\"noopener noreferrer\" href=\"https://bd103.dev/blog/2026-10-07-c-for-rust-programmers/#fn-size_t-and-ptrdiff_t\">[5]</a></sup></td>\n</tr>\n<tr>\n<td><code>i8</code></td>\n<td><code>int8_t</code></td>\n</tr>\n<tr>\n<td><code>i16</code></td>\n<td><code>int16_t</code></td>\n</tr>\n<tr>\n<td><code>i32</code></td>\n<td><code>int32_t</code></td>\n</tr>\n<tr>\n<td><code>i64</code></td>\n<td><code>int64_t</code></td>\n</tr>\n<tr>\n<td><code>isize</code></td>\n<td><code>ptrdiff_t</code><sup class=\"citation-ref\"><a target=\"_blank\" rel=\"noopener noreferrer\" href=\"https://bd103.dev/blog/2026-10-07-c-for-rust-programmers/#fn-size_t-and-ptrdiff_t\">[5]</a></sup></td>\n</tr>\n</tbody>\n</table>\n<h2>Error Handling Sucks</h2>\n<p>I really love Rust's error handling. <a target=\"_blank\" rel=\"noopener noreferrer\" href=\"https://doc.rust-lang.org/stable/std/result/enum.Result.html\"><code>Result</code></a> forces you to address errors, and sum types (<code>enum</code>s) and <code>match</code> statements make doing so really easy!</p>\n<p>C's error handling story, in comparison, is straight up tragic. It seems to boil down to functions returning a &quot;magic integer&quot; like -1 or a null pointer to signal there was an error. You can get a little bit more information by reading <a target=\"_blank\" rel=\"noopener noreferrer\" href=\"https://cppreference.com/c/error/errno\"><code>errno</code></a>, a thread-local integer that can be used to check for specific kinds of errors, but in terms of getting actual error messages and stack traces it is much harder.</p>\n<p>When writing C, one of the biggest things you'll notice is that the language will never force you to handle errors. It's up to you to remember that functions can fail. For example, here's a snippet of code from <a target=\"_blank\" rel=\"noopener noreferrer\" href=\"https://bd103.dev/blog/2026-10-07-c-for-rust-programmers/#null-terminated-strings\">Null-Terminated Strings</a>:</p>\n<pre><code class=\"language-c\"><span class=\"code-snippet\" data-language=\"C\"><span class=\"syntax-source syntax-c\"><span class=\"syntax-comment syntax-line syntax-double-slash syntax-c\"><span class=\"syntax-punctuation syntax-definition syntax-comment syntax-c\">//</span> Allocate enough room for the string and its null terminator.\n</span><span class=\"syntax-storage syntax-type syntax-c\">char</span><span class=\"syntax-keyword syntax-operator syntax-c\">*</span> reversed <span class=\"syntax-keyword syntax-operator syntax-assignment syntax-c\">=</span> <span class=\"syntax-meta syntax-function-call syntax-c\"><span class=\"syntax-support syntax-function syntax-C99 syntax-c\">malloc</span><span class=\"syntax-meta syntax-group syntax-c\"><span class=\"syntax-punctuation syntax-section syntax-group syntax-begin syntax-c\">(</span></span></span><span class=\"syntax-meta syntax-function-call syntax-c\"><span class=\"syntax-meta syntax-group syntax-c\">len <span class=\"syntax-keyword syntax-operator syntax-arithmetic syntax-c\">+</span> <span class=\"syntax-constant syntax-numeric syntax-c\">1</span></span></span><span class=\"syntax-meta syntax-function-call syntax-c\"><span class=\"syntax-meta syntax-group syntax-c\"><span class=\"syntax-punctuation syntax-section syntax-group syntax-end syntax-c\">)</span></span></span><span class=\"syntax-punctuation syntax-terminator syntax-c\">;</span>\n\n<span class=\"syntax-keyword syntax-control syntax-c\">for</span> <span class=\"syntax-meta syntax-group syntax-c\"><span class=\"syntax-punctuation syntax-section syntax-group syntax-begin syntax-c\">(</span><span class=\"syntax-storage syntax-type syntax-c\">int</span> i <span class=\"syntax-keyword syntax-operator syntax-assignment syntax-c\">=</span> <span class=\"syntax-constant syntax-numeric syntax-c\">0</span><span class=\"syntax-punctuation syntax-terminator syntax-c\">;</span> i <span class=\"syntax-keyword syntax-operator syntax-comparison syntax-c\">&lt;</span> len<span class=\"syntax-punctuation syntax-terminator syntax-c\">;</span> i<span class=\"syntax-keyword syntax-operator syntax-arithmetic syntax-c\">+</span><span class=\"syntax-keyword syntax-operator syntax-arithmetic syntax-c\">+</span><span class=\"syntax-punctuation syntax-section syntax-group syntax-end syntax-c\">)</span></span> <span class=\"syntax-meta syntax-block syntax-c\"><span class=\"syntax-punctuation syntax-section syntax-block syntax-begin syntax-c\">{</span>\n    reversed<span class=\"syntax-meta syntax-brackets syntax-c\"><span class=\"syntax-punctuation syntax-section syntax-brackets syntax-begin syntax-c\">[</span>i<span class=\"syntax-punctuation syntax-section syntax-brackets syntax-end syntax-c\">]</span></span> <span class=\"syntax-keyword syntax-operator syntax-assignment syntax-c\">=</span> forward<span class=\"syntax-meta syntax-brackets syntax-c\"><span class=\"syntax-punctuation syntax-section syntax-brackets syntax-begin syntax-c\">[</span>len <span class=\"syntax-keyword syntax-operator syntax-arithmetic syntax-c\">-</span> <span class=\"syntax-constant syntax-numeric syntax-c\">1</span> <span class=\"syntax-keyword syntax-operator syntax-arithmetic syntax-c\">-</span> i<span class=\"syntax-punctuation syntax-section syntax-brackets syntax-end syntax-c\">]</span></span><span class=\"syntax-punctuation syntax-terminator syntax-c\">;</span>\n<span class=\"syntax-punctuation syntax-section syntax-block syntax-end syntax-c\">}</span></span>\n</span></span></code></pre>\n<p>To new programmers, it's not immediately obvious that <a target=\"_blank\" rel=\"noopener noreferrer\" href=\"https://cppreference.com/c/memory/malloc\"><code>malloc()</code></a> can fail and return a null pointer. If your machine runs out of memory, <code>reversed[i]</code> will cause a segfault upon being accessed. In order to avoid unhelpful segfaults, the program should check for a null pointer and gracefully exit if one is found:</p>\n<pre><code class=\"language-c\"><span class=\"code-snippet\" data-language=\"C\"><span class=\"syntax-source syntax-c\"><span class=\"syntax-storage syntax-type syntax-c\">char</span><span class=\"syntax-keyword syntax-operator syntax-c\">*</span> reversed <span class=\"syntax-keyword syntax-operator syntax-assignment syntax-c\">=</span> <span class=\"syntax-meta syntax-function-call syntax-c\"><span class=\"syntax-support syntax-function syntax-C99 syntax-c\">malloc</span><span class=\"syntax-meta syntax-group syntax-c\"><span class=\"syntax-punctuation syntax-section syntax-group syntax-begin syntax-c\">(</span></span></span><span class=\"syntax-meta syntax-function-call syntax-c\"><span class=\"syntax-meta syntax-group syntax-c\">len <span class=\"syntax-keyword syntax-operator syntax-arithmetic syntax-c\">+</span> <span class=\"syntax-constant syntax-numeric syntax-c\">1</span></span></span><span class=\"syntax-meta syntax-function-call syntax-c\"><span class=\"syntax-meta syntax-group syntax-c\"><span class=\"syntax-punctuation syntax-section syntax-group syntax-end syntax-c\">)</span></span></span><span class=\"syntax-punctuation syntax-terminator syntax-c\">;</span>\n\n<span class=\"syntax-keyword syntax-control syntax-c\">if</span> <span class=\"syntax-meta syntax-group syntax-c\"><span class=\"syntax-punctuation syntax-section syntax-group syntax-begin syntax-c\">(</span>reversed <span class=\"syntax-keyword syntax-operator syntax-comparison syntax-c\">==</span> <span class=\"syntax-constant syntax-language syntax-c\">NULL</span><span class=\"syntax-punctuation syntax-section syntax-group syntax-end syntax-c\">)</span></span> <span class=\"syntax-meta syntax-block syntax-c\"><span class=\"syntax-punctuation syntax-section syntax-block syntax-begin syntax-c\">{</span>\n    <span class=\"syntax-meta syntax-function-call syntax-c\"><span class=\"syntax-support syntax-function syntax-C99 syntax-c\">perror</span><span class=\"syntax-meta syntax-group syntax-c\"><span class=\"syntax-punctuation syntax-section syntax-group syntax-begin syntax-c\">(</span></span></span><span class=\"syntax-meta syntax-function-call syntax-c\"><span class=\"syntax-meta syntax-group syntax-c\"><span class=\"syntax-string syntax-quoted syntax-double syntax-c\"><span class=\"syntax-punctuation syntax-definition syntax-string syntax-begin syntax-c\">&quot;</span>Error<span class=\"syntax-punctuation syntax-definition syntax-string syntax-end syntax-c\">&quot;</span></span></span></span><span class=\"syntax-meta syntax-function-call syntax-c\"><span class=\"syntax-meta syntax-group syntax-c\"><span class=\"syntax-punctuation syntax-section syntax-group syntax-end syntax-c\">)</span></span></span><span class=\"syntax-punctuation syntax-terminator syntax-c\">;</span>\n    <span class=\"syntax-meta syntax-function-call syntax-c\"><span class=\"syntax-support syntax-function syntax-C99 syntax-c\">exit</span><span class=\"syntax-meta syntax-group syntax-c\"><span class=\"syntax-punctuation syntax-section syntax-group syntax-begin syntax-c\">(</span></span></span><span class=\"syntax-meta syntax-function-call syntax-c\"><span class=\"syntax-meta syntax-group syntax-c\"><span class=\"syntax-constant syntax-numeric syntax-c\">1</span></span></span><span class=\"syntax-meta syntax-function-call syntax-c\"><span class=\"syntax-meta syntax-group syntax-c\"><span class=\"syntax-punctuation syntax-section syntax-group syntax-end syntax-c\">)</span></span></span><span class=\"syntax-punctuation syntax-terminator syntax-c\">;</span>\n<span class=\"syntax-punctuation syntax-section syntax-block syntax-end syntax-c\">}</span></span>\n</span></span></code></pre>\n<p>Doing so provides a much better experience than a segfault, or worse, other unintentional behavior:</p>\n<pre><code class=\"language-shellscript\"><span class=\"code-snippet\" data-language=\"Shell\"><span class=\"syntax-source syntax-shell syntax-bash\"><span class=\"syntax-meta syntax-function-call syntax-shell\"><span class=\"syntax-variable syntax-function syntax-shell\">$</span></span><span class=\"syntax-meta syntax-function-call syntax-arguments syntax-shell\"> ./main</span>\n<span class=\"syntax-meta syntax-function-call syntax-shell\"><span class=\"syntax-variable syntax-function syntax-shell\">Error:</span></span><span class=\"syntax-meta syntax-function-call syntax-arguments syntax-shell\"> Cannot allocate memory</span>\n</span></span></code></pre>\n<p>Of course, remembering to check every single allocated pointer isn't an amazing developer experience. An approach I played around with was recreating Rust's <code>Result</code> in C using tagged unions:</p>\n<pre><code class=\"language-c\"><span class=\"code-snippet\" data-language=\"C\"><span class=\"syntax-source syntax-c\"><span class=\"syntax-meta syntax-struct syntax-c\"><span class=\"syntax-storage syntax-type syntax-c\">struct</span> <span class=\"syntax-entity syntax-name syntax-struct syntax-c\">MallocResult</span> <span class=\"syntax-meta syntax-block syntax-c\"><span class=\"syntax-punctuation syntax-section syntax-block syntax-begin syntax-c\">{</span></span></span><span class=\"syntax-meta syntax-struct syntax-c\"><span class=\"syntax-meta syntax-block syntax-c\">\n    <span class=\"syntax-meta syntax-enum syntax-c\"><span class=\"syntax-storage syntax-type syntax-c\">enum</span> <span class=\"syntax-entity syntax-name syntax-enum syntax-c\">Tag</span> <span class=\"syntax-meta syntax-block syntax-c\"><span class=\"syntax-punctuation syntax-section syntax-block syntax-begin syntax-c\">{</span></span></span><span class=\"syntax-meta syntax-enum syntax-c\"><span class=\"syntax-meta syntax-block syntax-c\"> OK<span class=\"syntax-punctuation syntax-separator syntax-c\">,</span> ERROR </span></span><span class=\"syntax-meta syntax-enum syntax-c\"><span class=\"syntax-meta syntax-block syntax-c\"><span class=\"syntax-punctuation syntax-section syntax-block syntax-end syntax-c\">}</span></span></span> tag<span class=\"syntax-punctuation syntax-terminator syntax-c\">;</span>\n    <span class=\"syntax-meta syntax-union syntax-c\"><span class=\"syntax-storage syntax-type syntax-c\">union</span> <span class=\"syntax-entity syntax-name syntax-union syntax-c\">Value</span> <span class=\"syntax-meta syntax-block syntax-c\"><span class=\"syntax-punctuation syntax-section syntax-block syntax-begin syntax-c\">{</span></span></span><span class=\"syntax-meta syntax-union syntax-c\"><span class=\"syntax-meta syntax-block syntax-c\">\n        <span class=\"syntax-storage syntax-type syntax-c\">void</span><span class=\"syntax-keyword syntax-operator syntax-c\">*</span> ptr<span class=\"syntax-punctuation syntax-terminator syntax-c\">;</span>\n        <span class=\"syntax-storage syntax-type syntax-c\">char</span><span class=\"syntax-keyword syntax-operator syntax-c\">*</span> error_message<span class=\"syntax-punctuation syntax-terminator syntax-c\">;</span>\n    </span></span><span class=\"syntax-meta syntax-union syntax-c\"><span class=\"syntax-meta syntax-block syntax-c\"><span class=\"syntax-punctuation syntax-section syntax-block syntax-end syntax-c\">}</span></span></span> value<span class=\"syntax-punctuation syntax-terminator syntax-c\">;</span>\n</span></span><span class=\"syntax-meta syntax-struct syntax-c\"><span class=\"syntax-meta syntax-block syntax-c\"><span class=\"syntax-punctuation syntax-section syntax-block syntax-end syntax-c\">}</span></span></span><span class=\"syntax-punctuation syntax-terminator syntax-c\">;</span>\n</span></span></code></pre>\n<p>It's a complete mess to use, however, and there's <em>still</em> nothing stopping you from immediately accessing <code>result.value.ptr</code> without handling the error first. The lack of visibility modifiers like <code>private</code> and <code>public</code>, which could be used to prevent this, appear to be an intentional design decision. C places full trust in the programmer to <em>do things right™</em> and gives few facilities for contracts or safe abstractions.</p>\n<p>I personally disagree with this approach. I'm not some mastermind programming wizard who never makes mistakes. I'd much rather encode program requirements into the type system so that the compiler can check them for me!<sup class=\"citation-ref\"><a target=\"_blank\" rel=\"noopener noreferrer\" href=\"https://bd103.dev/blog/2026-10-07-c-for-rust-programmers/#fn-fearless-simd\">[6]</a></sup> That way, I can be reasonably certain that if the code compiles it was written correctly. But I digress.</p>\n<h2>Field Access Syntax</h2>\n<p>C has two different field access operators: <a target=\"_blank\" rel=\"noopener noreferrer\" href=\"https://cppreference.com/c/language/operator_member_access#Member_access\"><code>.</code></a> for values and <a target=\"_blank\" rel=\"noopener noreferrer\" href=\"https://cppreference.com/c/language/operator_member_access#Member_access_through_pointer\"><code>-&gt;</code></a> for pointers.</p>\n<pre><code class=\"language-c\"><span class=\"code-snippet\" data-language=\"C\"><span class=\"syntax-source syntax-c\"><span class=\"syntax-meta syntax-struct syntax-c\"><span class=\"syntax-storage syntax-type syntax-c\">struct</span> <span class=\"syntax-entity syntax-name syntax-struct syntax-c\">Foo</span> <span class=\"syntax-meta syntax-block syntax-c\"><span class=\"syntax-punctuation syntax-section syntax-block syntax-begin syntax-c\">{</span></span></span><span class=\"syntax-meta syntax-struct syntax-c\"><span class=\"syntax-meta syntax-block syntax-c\">\n    <span class=\"syntax-storage syntax-type syntax-c\">int</span> field<span class=\"syntax-punctuation syntax-terminator syntax-c\">;</span>\n</span></span><span class=\"syntax-meta syntax-struct syntax-c\"><span class=\"syntax-meta syntax-block syntax-c\"><span class=\"syntax-punctuation syntax-section syntax-block syntax-end syntax-c\">}</span></span></span><span class=\"syntax-punctuation syntax-terminator syntax-c\">;</span>\n\n<span class=\"syntax-storage syntax-type syntax-c\">struct</span> Foo value <span class=\"syntax-keyword syntax-operator syntax-assignment syntax-c\">=</span> <span class=\"syntax-meta syntax-block syntax-c\"><span class=\"syntax-punctuation syntax-section syntax-block syntax-begin syntax-c\">{</span> <span class=\"syntax-constant syntax-numeric syntax-c\">103</span> <span class=\"syntax-punctuation syntax-section syntax-block syntax-end syntax-c\">}</span></span><span class=\"syntax-punctuation syntax-terminator syntax-c\">;</span>\n<span class=\"syntax-storage syntax-type syntax-c\">struct</span> Foo<span class=\"syntax-keyword syntax-operator syntax-c\">*</span> ptr <span class=\"syntax-keyword syntax-operator syntax-assignment syntax-c\">=</span> <span class=\"syntax-keyword syntax-operator syntax-c\">&amp;</span>value<span class=\"syntax-punctuation syntax-terminator syntax-c\">;</span>\n\n<span class=\"syntax-comment syntax-line syntax-double-slash syntax-c\"><span class=\"syntax-punctuation syntax-definition syntax-comment syntax-c\">//</span> Accessing the field directly.\n</span><span class=\"syntax-meta syntax-function-call syntax-c\"><span class=\"syntax-variable syntax-function syntax-c\">printf</span><span class=\"syntax-meta syntax-group syntax-c\"><span class=\"syntax-punctuation syntax-section syntax-group syntax-begin syntax-c\">(</span></span></span><span class=\"syntax-meta syntax-function-call syntax-c\"><span class=\"syntax-meta syntax-group syntax-c\"><span class=\"syntax-string syntax-quoted syntax-double syntax-c\"><span class=\"syntax-punctuation syntax-definition syntax-string syntax-begin syntax-c\">&quot;</span><span class=\"syntax-constant syntax-other syntax-placeholder syntax-c\">%d</span><span class=\"syntax-constant syntax-character syntax-escape syntax-c\">\\n</span><span class=\"syntax-punctuation syntax-definition syntax-string syntax-end syntax-c\">&quot;</span></span><span class=\"syntax-punctuation syntax-separator syntax-c\">,</span> value<span class=\"syntax-punctuation syntax-accessor syntax-c\">.</span><span class=\"syntax-variable syntax-other syntax-member syntax-c\">field</span></span><span class=\"syntax-meta syntax-group syntax-c\"><span class=\"syntax-punctuation syntax-section syntax-group syntax-end syntax-c\">)</span></span></span><span class=\"syntax-punctuation syntax-terminator syntax-c\">;</span>\n\n<span class=\"syntax-comment syntax-line syntax-double-slash syntax-c\"><span class=\"syntax-punctuation syntax-definition syntax-comment syntax-c\">//</span> Accessing the field through a pointer.\n</span><span class=\"syntax-meta syntax-function-call syntax-c\"><span class=\"syntax-variable syntax-function syntax-c\">printf</span><span class=\"syntax-meta syntax-group syntax-c\"><span class=\"syntax-punctuation syntax-section syntax-group syntax-begin syntax-c\">(</span></span></span><span class=\"syntax-meta syntax-function-call syntax-c\"><span class=\"syntax-meta syntax-group syntax-c\"><span class=\"syntax-string syntax-quoted syntax-double syntax-c\"><span class=\"syntax-punctuation syntax-definition syntax-string syntax-begin syntax-c\">&quot;</span><span class=\"syntax-constant syntax-other syntax-placeholder syntax-c\">%d</span><span class=\"syntax-constant syntax-character syntax-escape syntax-c\">\\n</span><span class=\"syntax-punctuation syntax-definition syntax-string syntax-end syntax-c\">&quot;</span></span><span class=\"syntax-punctuation syntax-separator syntax-c\">,</span> ptr<span class=\"syntax-punctuation syntax-accessor syntax-c\">-&gt;</span>field</span><span class=\"syntax-meta syntax-group syntax-c\"><span class=\"syntax-punctuation syntax-section syntax-group syntax-end syntax-c\">)</span></span></span><span class=\"syntax-punctuation syntax-terminator syntax-c\">;</span>\n</span></span></code></pre>\n<p>This caught me off guard at first, as Rust uses <code>.</code> for everything.</p>\n<p><picture class=\"article-picture article-picture-fallback\" style=\"--image-ratio:16 / 9\"><img src=\"https://bd103.dev/blog/2026-10-07-c-for-rust-programmers/i-put-that-dot-on-everything.jpg\" alt=\"An old lady holding Frank&#39;s Red Hot sauce, except Ferris the crab is photoshopped on top saying &#39;I put that . on everything&#39;\" loading=\"eager\" decoding=\"async\" fetchpriority=\"high\" referrerpolicy=\"no-referrer\" class=\"progressive-image\"></picture></p>\n<p>If your curious, <a target=\"_blank\" rel=\"noopener noreferrer\" href=\"https://stackoverflow.com/a/13366168\">this Stack Overflow write up</a> provides some interesting history on why the <code>-&gt;</code> operator exists.<sup class=\"citation-ref\"><a target=\"_blank\" rel=\"noopener noreferrer\" href=\"https://bd103.dev/blog/2026-10-07-c-for-rust-programmers/#fn-cursed-arrow-operator\">[7]</a></sup></p>\n<h2>Arrays Become Pointers for Fun</h2>\n<p>Arrays have some weird nuance to them. Sometimes they are plain values with their length accessible using <a target=\"_blank\" rel=\"noopener noreferrer\" href=\"https://cppreference.com/c/language/sizeof\"><code>sizeof()</code></a>, other times they are pointers with an unknown size. In general, this is determined by whether you are handling the array within the function it was defined or not.</p>\n<p>To showcase what I mean, here's a very simple C program that prints the size of two arrays:</p>\n<pre><code class=\"language-c\"><span class=\"code-snippet\" data-language=\"C\"><span class=\"syntax-source syntax-c\"><span class=\"syntax-storage syntax-type syntax-c\">char</span> declared_size<span class=\"syntax-meta syntax-brackets syntax-c\"><span class=\"syntax-punctuation syntax-section syntax-brackets syntax-begin syntax-c\">[</span><span class=\"syntax-constant syntax-numeric syntax-c\">3</span><span class=\"syntax-punctuation syntax-section syntax-brackets syntax-end syntax-c\">]</span></span> <span class=\"syntax-keyword syntax-operator syntax-assignment syntax-c\">=</span> <span class=\"syntax-meta syntax-block syntax-c\"><span class=\"syntax-punctuation syntax-section syntax-block syntax-begin syntax-c\">{</span> <span class=\"syntax-constant syntax-numeric syntax-c\">1</span><span class=\"syntax-punctuation syntax-separator syntax-c\">,</span> <span class=\"syntax-constant syntax-numeric syntax-c\">2</span><span class=\"syntax-punctuation syntax-separator syntax-c\">,</span> <span class=\"syntax-constant syntax-numeric syntax-c\">3</span> <span class=\"syntax-punctuation syntax-section syntax-block syntax-end syntax-c\">}</span></span><span class=\"syntax-punctuation syntax-terminator syntax-c\">;</span>\n<span class=\"syntax-storage syntax-type syntax-c\">char</span> inferred_size<span class=\"syntax-meta syntax-brackets syntax-c\"><span class=\"syntax-punctuation syntax-section syntax-brackets syntax-begin syntax-c\">[</span><span class=\"syntax-punctuation syntax-section syntax-brackets syntax-end syntax-c\">]</span></span> <span class=\"syntax-keyword syntax-operator syntax-assignment syntax-c\">=</span> <span class=\"syntax-meta syntax-block syntax-c\"><span class=\"syntax-punctuation syntax-section syntax-block syntax-begin syntax-c\">{</span> <span class=\"syntax-constant syntax-numeric syntax-c\">4</span><span class=\"syntax-punctuation syntax-separator syntax-c\">,</span> <span class=\"syntax-constant syntax-numeric syntax-c\">5</span><span class=\"syntax-punctuation syntax-separator syntax-c\">,</span> <span class=\"syntax-constant syntax-numeric syntax-c\">6</span> <span class=\"syntax-punctuation syntax-section syntax-block syntax-end syntax-c\">}</span></span><span class=\"syntax-punctuation syntax-terminator syntax-c\">;</span>\n\n<span class=\"syntax-meta syntax-function-call syntax-c\"><span class=\"syntax-variable syntax-function syntax-c\">printf</span><span class=\"syntax-meta syntax-group syntax-c\"><span class=\"syntax-punctuation syntax-section syntax-group syntax-begin syntax-c\">(</span></span></span><span class=\"syntax-meta syntax-function-call syntax-c\"><span class=\"syntax-meta syntax-group syntax-c\"><span class=\"syntax-string syntax-quoted syntax-double syntax-c\"><span class=\"syntax-punctuation syntax-definition syntax-string syntax-begin syntax-c\">&quot;</span>Declared size (main): <span class=\"syntax-constant syntax-other syntax-placeholder syntax-c\">%ld</span> bytes<span class=\"syntax-constant syntax-character syntax-escape syntax-c\">\\n</span><span class=\"syntax-punctuation syntax-definition syntax-string syntax-end syntax-c\">&quot;</span></span><span class=\"syntax-punctuation syntax-separator syntax-c\">,</span> <span class=\"syntax-keyword syntax-operator syntax-word syntax-c\">sizeof</span><span class=\"syntax-meta syntax-group syntax-c\"><span class=\"syntax-punctuation syntax-section syntax-group syntax-begin syntax-c\">(</span></span><span class=\"syntax-meta syntax-group syntax-c\">declared_size</span><span class=\"syntax-meta syntax-group syntax-c\"><span class=\"syntax-punctuation syntax-section syntax-group syntax-end syntax-c\">)</span></span></span><span class=\"syntax-meta syntax-group syntax-c\"><span class=\"syntax-punctuation syntax-section syntax-group syntax-end syntax-c\">)</span></span></span><span class=\"syntax-punctuation syntax-terminator syntax-c\">;</span>\n<span class=\"syntax-meta syntax-function-call syntax-c\"><span class=\"syntax-variable syntax-function syntax-c\">printf</span><span class=\"syntax-meta syntax-group syntax-c\"><span class=\"syntax-punctuation syntax-section syntax-group syntax-begin syntax-c\">(</span></span></span><span class=\"syntax-meta syntax-function-call syntax-c\"><span class=\"syntax-meta syntax-group syntax-c\"><span class=\"syntax-string syntax-quoted syntax-double syntax-c\"><span class=\"syntax-punctuation syntax-definition syntax-string syntax-begin syntax-c\">&quot;</span>Inferred size (main): <span class=\"syntax-constant syntax-other syntax-placeholder syntax-c\">%ld</span> bytes<span class=\"syntax-constant syntax-character syntax-escape syntax-c\">\\n</span><span class=\"syntax-punctuation syntax-definition syntax-string syntax-end syntax-c\">&quot;</span></span><span class=\"syntax-punctuation syntax-separator syntax-c\">,</span> <span class=\"syntax-keyword syntax-operator syntax-word syntax-c\">sizeof</span><span class=\"syntax-meta syntax-group syntax-c\"><span class=\"syntax-punctuation syntax-section syntax-group syntax-begin syntax-c\">(</span></span><span class=\"syntax-meta syntax-group syntax-c\">inferred_size</span><span class=\"syntax-meta syntax-group syntax-c\"><span class=\"syntax-punctuation syntax-section syntax-group syntax-end syntax-c\">)</span></span></span><span class=\"syntax-meta syntax-group syntax-c\"><span class=\"syntax-punctuation syntax-section syntax-group syntax-end syntax-c\">)</span></span></span><span class=\"syntax-punctuation syntax-terminator syntax-c\">;</span>\n</span></span></code></pre>\n<p>When run, this programs tells you that both arrays take 3 bytes of memory. Good!</p>\n<pre><code class=\"language-shellscript\"><span class=\"code-snippet\" data-language=\"Shell\"><span class=\"syntax-source syntax-shell syntax-bash\"><span class=\"syntax-meta syntax-function-call syntax-shell\"><span class=\"syntax-variable syntax-function syntax-shell\">$</span></span><span class=\"syntax-meta syntax-function-call syntax-arguments syntax-shell\"> ./main</span>\n<span class=\"syntax-meta syntax-function-call syntax-shell\"><span class=\"syntax-variable syntax-function syntax-shell\">Declared</span></span><span class=\"syntax-meta syntax-function-call syntax-arguments syntax-shell\"> size (main</span><span class=\"syntax-meta syntax-function-call syntax-shell\"></span><span class=\"syntax-meta syntax-post-cmd syntax-shell\">)</span><span class=\"syntax-meta syntax-function-call syntax-shell\"><span class=\"syntax-support syntax-function syntax-colon syntax-shell\">:</span></span><span class=\"syntax-meta syntax-function-call syntax-arguments syntax-shell\"> 3 bytes</span>\n<span class=\"syntax-meta syntax-function-call syntax-shell\"><span class=\"syntax-variable syntax-function syntax-shell\">Inferred</span></span><span class=\"syntax-meta syntax-function-call syntax-arguments syntax-shell\"> size (main</span><span class=\"syntax-meta syntax-function-call syntax-shell\"></span><span class=\"syntax-meta syntax-post-cmd syntax-shell\">)</span><span class=\"syntax-meta syntax-function-call syntax-shell\"><span class=\"syntax-support syntax-function syntax-colon syntax-shell\">:</span></span><span class=\"syntax-meta syntax-function-call syntax-arguments syntax-shell\"> 3 bytes</span>\n</span></span></code></pre>\n<p>Now, let's make a slight modification. Let's pass <code>declared_size</code> and <code>inferred_size</code> through a function before printing its size:</p>\n<pre><code class=\"language-c\"><span class=\"code-snippet\" data-language=\"C\"><span class=\"syntax-source syntax-c\"><span class=\"syntax-storage syntax-type syntax-c\">void</span> <span class=\"syntax-meta syntax-function syntax-c\"><span class=\"syntax-entity syntax-name syntax-function syntax-c\">function</span></span><span class=\"syntax-meta syntax-function syntax-parameters syntax-c\"><span class=\"syntax-meta syntax-group syntax-c\"><span class=\"syntax-punctuation syntax-section syntax-group syntax-begin syntax-c\">(</span></span></span><span class=\"syntax-meta syntax-function syntax-parameters syntax-c\"><span class=\"syntax-meta syntax-group syntax-c\"><span class=\"syntax-storage syntax-type syntax-c\">char</span> <span class=\"syntax-variable syntax-parameter syntax-c\">declared_size</span><span class=\"syntax-meta syntax-brackets syntax-c\"><span class=\"syntax-punctuation syntax-section syntax-brackets syntax-begin syntax-c\">[</span><span class=\"syntax-constant syntax-numeric syntax-c\">3</span><span class=\"syntax-punctuation syntax-section syntax-brackets syntax-end syntax-c\">]</span></span><span class=\"syntax-punctuation syntax-separator syntax-c\">,</span> <span class=\"syntax-storage syntax-type syntax-c\">char</span> <span class=\"syntax-variable syntax-parameter syntax-c\">inferred_size</span><span class=\"syntax-meta syntax-brackets syntax-c\"><span class=\"syntax-punctuation syntax-section syntax-brackets syntax-begin syntax-c\">[</span><span class=\"syntax-punctuation syntax-section syntax-brackets syntax-end syntax-c\">]</span></span><span class=\"syntax-punctuation syntax-section syntax-group syntax-end syntax-c\">)</span></span></span><span class=\"syntax-meta syntax-function syntax-c\"> </span><span class=\"syntax-meta syntax-function syntax-c\"><span class=\"syntax-meta syntax-block syntax-c\"><span class=\"syntax-punctuation syntax-section syntax-block syntax-begin syntax-c\">{</span></span></span><span class=\"syntax-meta syntax-function syntax-c\"><span class=\"syntax-meta syntax-block syntax-c\">\n    <span class=\"syntax-meta syntax-function-call syntax-c\"><span class=\"syntax-support syntax-function syntax-C99 syntax-c\">printf</span><span class=\"syntax-meta syntax-group syntax-c\"><span class=\"syntax-punctuation syntax-section syntax-group syntax-begin syntax-c\">(</span></span></span><span class=\"syntax-meta syntax-function-call syntax-c\"><span class=\"syntax-meta syntax-group syntax-c\"><span class=\"syntax-string syntax-quoted syntax-double syntax-c\"><span class=\"syntax-punctuation syntax-definition syntax-string syntax-begin syntax-c\">&quot;</span>Declared size (function): <span class=\"syntax-constant syntax-other syntax-placeholder syntax-c\">%ld</span> bytes<span class=\"syntax-constant syntax-character syntax-escape syntax-c\">\\n</span><span class=\"syntax-punctuation syntax-definition syntax-string syntax-end syntax-c\">&quot;</span></span><span class=\"syntax-punctuation syntax-separator syntax-c\">,</span> <span class=\"syntax-keyword syntax-operator syntax-word syntax-c\">sizeof</span><span class=\"syntax-meta syntax-group syntax-c\"><span class=\"syntax-punctuation syntax-section syntax-group syntax-begin syntax-c\">(</span></span><span class=\"syntax-meta syntax-group syntax-c\">declared_size</span><span class=\"syntax-meta syntax-group syntax-c\"><span class=\"syntax-punctuation syntax-section syntax-group syntax-end syntax-c\">)</span></span></span></span><span class=\"syntax-meta syntax-function-call syntax-c\"><span class=\"syntax-meta syntax-group syntax-c\"><span class=\"syntax-punctuation syntax-section syntax-group syntax-end syntax-c\">)</span></span></span><span class=\"syntax-punctuation syntax-terminator syntax-c\">;</span>\n    <span class=\"syntax-meta syntax-function-call syntax-c\"><span class=\"syntax-support syntax-function syntax-C99 syntax-c\">printf</span><span class=\"syntax-meta syntax-group syntax-c\"><span class=\"syntax-punctuation syntax-section syntax-group syntax-begin syntax-c\">(</span></span></span><span class=\"syntax-meta syntax-function-call syntax-c\"><span class=\"syntax-meta syntax-group syntax-c\"><span class=\"syntax-string syntax-quoted syntax-double syntax-c\"><span class=\"syntax-punctuation syntax-definition syntax-string syntax-begin syntax-c\">&quot;</span>Inferred size (function): <span class=\"syntax-constant syntax-other syntax-placeholder syntax-c\">%ld</span> bytes<span class=\"syntax-constant syntax-character syntax-escape syntax-c\">\\n</span><span class=\"syntax-punctuation syntax-definition syntax-string syntax-end syntax-c\">&quot;</span></span><span class=\"syntax-punctuation syntax-separator syntax-c\">,</span> <span class=\"syntax-keyword syntax-operator syntax-word syntax-c\">sizeof</span><span class=\"syntax-meta syntax-group syntax-c\"><span class=\"syntax-punctuation syntax-section syntax-group syntax-begin syntax-c\">(</span></span><span class=\"syntax-meta syntax-group syntax-c\">inferred_size</span><span class=\"syntax-meta syntax-group syntax-c\"><span class=\"syntax-punctuation syntax-section syntax-group syntax-end syntax-c\">)</span></span></span></span><span class=\"syntax-meta syntax-function-call syntax-c\"><span class=\"syntax-meta syntax-group syntax-c\"><span class=\"syntax-punctuation syntax-section syntax-group syntax-end syntax-c\">)</span></span></span><span class=\"syntax-punctuation syntax-terminator syntax-c\">;</span>\n</span></span><span class=\"syntax-meta syntax-function syntax-c\"><span class=\"syntax-meta syntax-block syntax-c\"><span class=\"syntax-punctuation syntax-section syntax-block syntax-end syntax-c\">}</span></span></span>\n</span></span></code></pre>\n<p>None of the logic changed, the arrays are identical to the previous example, however now the program reports each array takes <strong>8 bytes of memory</strong>:</p>\n<pre><code class=\"language-shellscript\"><span class=\"code-snippet\" data-language=\"Shell\"><span class=\"syntax-source syntax-shell syntax-bash\"><span class=\"syntax-meta syntax-function-call syntax-shell\"><span class=\"syntax-variable syntax-function syntax-shell\">$</span></span><span class=\"syntax-meta syntax-function-call syntax-arguments syntax-shell\"> ./main</span>\n<span class=\"syntax-meta syntax-function-call syntax-shell\"><span class=\"syntax-variable syntax-function syntax-shell\">Declared</span></span><span class=\"syntax-meta syntax-function-call syntax-arguments syntax-shell\"> size (function</span><span class=\"syntax-meta syntax-function-call syntax-shell\"></span><span class=\"syntax-meta syntax-post-cmd syntax-shell\">)</span><span class=\"syntax-meta syntax-function-call syntax-shell\"><span class=\"syntax-support syntax-function syntax-colon syntax-shell\">:</span></span><span class=\"syntax-meta syntax-function-call syntax-arguments syntax-shell\"> 8 bytes</span>\n<span class=\"syntax-meta syntax-function-call syntax-shell\"><span class=\"syntax-variable syntax-function syntax-shell\">Inferred</span></span><span class=\"syntax-meta syntax-function-call syntax-arguments syntax-shell\"> size (function</span><span class=\"syntax-meta syntax-function-call syntax-shell\"></span><span class=\"syntax-meta syntax-post-cmd syntax-shell\">)</span><span class=\"syntax-meta syntax-function-call syntax-shell\"><span class=\"syntax-support syntax-function syntax-colon syntax-shell\">:</span></span><span class=\"syntax-meta syntax-function-call syntax-arguments syntax-shell\"> 8 bytes</span>\n</span></span></code></pre>\n<p>Why? Because any array passed through a function is <em>implicitly converted</em> to a pointer to the first element. From the C compiler's perspective, the above function actually had the following type signature:</p>\n<pre><code class=\"language-c\"><span class=\"code-snippet\" data-language=\"C\"><span class=\"syntax-source syntax-c\"><span class=\"syntax-storage syntax-type syntax-c\">void</span> <span class=\"syntax-meta syntax-function syntax-c\"><span class=\"syntax-entity syntax-name syntax-function syntax-c\">function</span></span><span class=\"syntax-meta syntax-function syntax-parameters syntax-c\"><span class=\"syntax-meta syntax-group syntax-c\"><span class=\"syntax-punctuation syntax-section syntax-group syntax-begin syntax-c\">(</span></span></span><span class=\"syntax-meta syntax-function syntax-parameters syntax-c\"><span class=\"syntax-meta syntax-group syntax-c\"><span class=\"syntax-storage syntax-type syntax-c\">char</span><span class=\"syntax-keyword syntax-operator syntax-c\">*</span> <span class=\"syntax-variable syntax-parameter syntax-c\">declared_size</span><span class=\"syntax-punctuation syntax-separator syntax-c\">,</span> <span class=\"syntax-storage syntax-type syntax-c\">char</span><span class=\"syntax-keyword syntax-operator syntax-c\">*</span> <span class=\"syntax-variable syntax-parameter syntax-c\">inferred_size</span><span class=\"syntax-punctuation syntax-section syntax-group syntax-end syntax-c\">)</span></span></span><span class=\"syntax-punctuation syntax-terminator syntax-c\">;</span>\n</span></span></code></pre>\n<p>This is why it confusingly looked like each array was 8 bytes long. The arrays themselves are 3 bytes, but the pointers take up 8 bytes of memory! Handily, Clang raises a warning when you run <code>sizeof()</code> on the pointer form of an array, making it easier to catch this mistake:</p>\n<pre><code class=\"language-shellscript\"><span class=\"code-snippet\" data-language=\"Shell\"><span class=\"syntax-source syntax-shell syntax-bash\"><span class=\"syntax-meta syntax-function-call syntax-shell\"><span class=\"syntax-variable syntax-function syntax-shell\">$</span></span><span class=\"syntax-meta syntax-function-call syntax-arguments syntax-shell\"> clang main.c</span>\n<span class=\"syntax-meta syntax-function-call syntax-shell\"><span class=\"syntax-variable syntax-function syntax-shell\">06-arrays/main.c:5:59:</span></span><span class=\"syntax-meta syntax-function-call syntax-arguments syntax-shell\"> warning: sizeof on array function parameter will return size of <span class=\"syntax-string syntax-quoted syntax-single syntax-shell\"><span class=\"syntax-punctuation syntax-definition syntax-string syntax-begin syntax-shell\">&#39;</span>char *<span class=\"syntax-punctuation syntax-definition syntax-string syntax-end syntax-shell\">&#39;</span></span></span>\n      <span class=\"syntax-meta syntax-function-call syntax-shell\"><span class=\"syntax-variable syntax-function syntax-shell\">instead</span></span><span class=\"syntax-meta syntax-function-call syntax-arguments syntax-shell\"> of <span class=\"syntax-string syntax-quoted syntax-single syntax-shell\"><span class=\"syntax-punctuation syntax-definition syntax-string syntax-begin syntax-shell\">&#39;</span>char[3]<span class=\"syntax-punctuation syntax-definition syntax-string syntax-end syntax-shell\">&#39;</span></span> <span class=\"syntax-keyword syntax-control syntax-regexp syntax-set syntax-begin syntax-shell\">[</span>-Wsizeof<span class=\"syntax-keyword syntax-operator syntax-word syntax-shell\">-</span>array<span class=\"syntax-keyword syntax-operator syntax-word syntax-shell\">-</span>argument<span class=\"syntax-keyword syntax-control syntax-regexp syntax-set syntax-end syntax-shell\">]</span></span>\n    <span class=\"syntax-meta syntax-function-call syntax-shell\"><span class=\"syntax-variable syntax-function syntax-shell\">5</span></span> <span class=\"syntax-keyword syntax-operator syntax-logical syntax-pipe syntax-shell\">|</span>     <span class=\"syntax-meta syntax-function-call syntax-shell\"><span class=\"syntax-variable syntax-function syntax-shell\">printf</span></span><span class=\"syntax-meta syntax-function-call syntax-arguments syntax-shell\">(<span class=\"syntax-string syntax-quoted syntax-double syntax-shell\"><span class=\"syntax-punctuation syntax-definition syntax-string syntax-begin syntax-shell\">&quot;</span>Declared size (function): %ld bytes\\n<span class=\"syntax-punctuation syntax-definition syntax-string syntax-end syntax-shell\">&quot;</span></span>, sizeof(declared_size</span><span class=\"syntax-meta syntax-function-call syntax-shell\"></span><span class=\"syntax-meta syntax-post-cmd syntax-shell\">)</span><span class=\"syntax-meta syntax-function-call syntax-shell\"></span><span class=\"syntax-meta syntax-post-cmd syntax-shell\">)</span><span class=\"syntax-keyword syntax-operator syntax-logical syntax-continue syntax-shell\">;</span>\n      <span class=\"syntax-meta syntax-function-call syntax-shell\"></span><span class=\"syntax-keyword syntax-operator syntax-logical syntax-pipe syntax-shell\">|</span>                                                           <span class=\"syntax-meta syntax-function-call syntax-shell\"><span class=\"syntax-variable syntax-function syntax-shell\">^</span></span>\n<span class=\"syntax-meta syntax-function-call syntax-shell\"><span class=\"syntax-variable syntax-function syntax-shell\">06-arrays/main.c:4:20:</span></span><span class=\"syntax-meta syntax-function-call syntax-arguments syntax-shell\"> note: declared here</span>\n    <span class=\"syntax-meta syntax-function-call syntax-shell\"><span class=\"syntax-variable syntax-function syntax-shell\">4</span></span> <span class=\"syntax-keyword syntax-operator syntax-logical syntax-pipe syntax-shell\">|</span> <span class=\"syntax-meta syntax-function-call syntax-shell\"><span class=\"syntax-variable syntax-function syntax-shell\">void</span></span><span class=\"syntax-meta syntax-function-call syntax-arguments syntax-shell\"> function(char declared_size<span class=\"syntax-keyword syntax-control syntax-regexp syntax-set syntax-begin syntax-shell\">[</span>3<span class=\"syntax-keyword syntax-control syntax-regexp syntax-set syntax-end syntax-shell\">]</span>, char inferred_size<span class=\"syntax-keyword syntax-control syntax-regexp syntax-set syntax-begin syntax-shell\">[</span>]) <span class=\"syntax-meta syntax-group syntax-expansion syntax-brace syntax-shell\"><span class=\"syntax-punctuation syntax-section syntax-expansion syntax-brace syntax-begin syntax-shell\">{</span>\n      |                    ^\n06-arrays/main.c:6:59: warning: sizeof on array function parameter will return size of <span class=\"syntax-string syntax-quoted syntax-single syntax-shell\"><span class=\"syntax-punctuation syntax-definition syntax-string syntax-begin syntax-shell\">&#39;</span>char *<span class=\"syntax-punctuation syntax-definition syntax-string syntax-end syntax-shell\">&#39;</span></span>\n      instead of <span class=\"syntax-string syntax-quoted syntax-single syntax-shell\"><span class=\"syntax-punctuation syntax-definition syntax-string syntax-begin syntax-shell\">&#39;</span>char[]<span class=\"syntax-punctuation syntax-definition syntax-string syntax-end syntax-shell\">&#39;</span></span> <span class=\"syntax-keyword syntax-control syntax-regexp syntax-set syntax-begin syntax-shell\">[</span>-Wsizeof<span class=\"syntax-keyword syntax-operator syntax-word syntax-shell\">-</span>array<span class=\"syntax-keyword syntax-operator syntax-word syntax-shell\">-</span>argument<span class=\"syntax-keyword syntax-control syntax-regexp syntax-set syntax-end syntax-shell\">]</span>\n    6 |     printf(<span class=\"syntax-string syntax-quoted syntax-double syntax-shell\"><span class=\"syntax-punctuation syntax-definition syntax-string syntax-begin syntax-shell\">&quot;</span>Inferred size (function): %ld bytes\\n<span class=\"syntax-punctuation syntax-definition syntax-string syntax-end syntax-shell\">&quot;</span></span><span class=\"syntax-punctuation syntax-separator syntax-shell\">,</span> sizeof(inferred_size));\n      |                                                           ^\n06-arrays/main.c:4:43: note: declared here\n    4 | void function(char declared_size<span class=\"syntax-keyword syntax-control syntax-regexp syntax-set syntax-begin syntax-shell\">[</span>3<span class=\"syntax-keyword syntax-control syntax-regexp syntax-set syntax-end syntax-shell\">]</span><span class=\"syntax-punctuation syntax-separator syntax-shell\">,</span> char inferred_size<span class=\"syntax-keyword syntax-control syntax-regexp syntax-set syntax-begin syntax-shell\">[</span>]) <span class=\"syntax-meta syntax-group syntax-expansion syntax-brace syntax-shell\"><span class=\"syntax-punctuation syntax-section syntax-expansion syntax-brace syntax-begin syntax-shell\">{</span>\n      |                                           ^\n2 warnings generated.\n</span></span></span></span></span></code></pre>\n<h2>Oh Yeah References Don't Exist</h2>\n<p>I'd be remiss if I didn't mention it once. C has no borrow checking, and no concept of references. It's all <a target=\"_blank\" rel=\"noopener noreferrer\" href=\"https://doc.rust-lang.org/stable/std/primitive.pointer.html\">raw pointers</a>. This means you can do fun pointer arithmetic like so:</p>\n<pre><code class=\"language-c\"><span class=\"code-snippet\" data-language=\"C\"><span class=\"syntax-source syntax-c\"><span class=\"syntax-storage syntax-type syntax-c\">int</span> array<span class=\"syntax-meta syntax-brackets syntax-c\"><span class=\"syntax-punctuation syntax-section syntax-brackets syntax-begin syntax-c\">[</span><span class=\"syntax-punctuation syntax-section syntax-brackets syntax-end syntax-c\">]</span></span> <span class=\"syntax-keyword syntax-operator syntax-assignment syntax-c\">=</span> <span class=\"syntax-meta syntax-block syntax-c\"><span class=\"syntax-punctuation syntax-section syntax-block syntax-begin syntax-c\">{</span> <span class=\"syntax-constant syntax-numeric syntax-c\">0</span><span class=\"syntax-punctuation syntax-separator syntax-c\">,</span> <span class=\"syntax-constant syntax-numeric syntax-c\">1</span><span class=\"syntax-punctuation syntax-separator syntax-c\">,</span> <span class=\"syntax-constant syntax-numeric syntax-c\">2</span><span class=\"syntax-punctuation syntax-separator syntax-c\">,</span> <span class=\"syntax-constant syntax-numeric syntax-c\">3</span><span class=\"syntax-punctuation syntax-separator syntax-c\">,</span> <span class=\"syntax-constant syntax-numeric syntax-c\">4</span><span class=\"syntax-punctuation syntax-separator syntax-c\">,</span> <span class=\"syntax-constant syntax-numeric syntax-c\">5</span> <span class=\"syntax-punctuation syntax-section syntax-block syntax-end syntax-c\">}</span></span><span class=\"syntax-punctuation syntax-terminator syntax-c\">;</span>\n\n<span class=\"syntax-comment syntax-line syntax-double-slash syntax-c\"><span class=\"syntax-punctuation syntax-definition syntax-comment syntax-c\">//</span> Woah, iterating over pointers instead of indexes!\n</span><span class=\"syntax-keyword syntax-control syntax-c\">for</span> <span class=\"syntax-meta syntax-group syntax-c\"><span class=\"syntax-punctuation syntax-section syntax-group syntax-begin syntax-c\">(</span><span class=\"syntax-storage syntax-type syntax-c\">int</span><span class=\"syntax-keyword syntax-operator syntax-c\">*</span> x <span class=\"syntax-keyword syntax-operator syntax-assignment syntax-c\">=</span> <span class=\"syntax-keyword syntax-operator syntax-c\">&amp;</span>array<span class=\"syntax-meta syntax-brackets syntax-c\"><span class=\"syntax-punctuation syntax-section syntax-brackets syntax-begin syntax-c\">[</span><span class=\"syntax-constant syntax-numeric syntax-c\">0</span><span class=\"syntax-punctuation syntax-section syntax-brackets syntax-end syntax-c\">]</span></span><span class=\"syntax-punctuation syntax-terminator syntax-c\">;</span> x <span class=\"syntax-keyword syntax-operator syntax-comparison syntax-c\">&lt;</span> <span class=\"syntax-keyword syntax-operator syntax-c\">&amp;</span>array<span class=\"syntax-meta syntax-brackets syntax-c\"><span class=\"syntax-punctuation syntax-section syntax-brackets syntax-begin syntax-c\">[</span><span class=\"syntax-constant syntax-numeric syntax-c\">6</span><span class=\"syntax-punctuation syntax-section syntax-brackets syntax-end syntax-c\">]</span></span><span class=\"syntax-punctuation syntax-terminator syntax-c\">;</span> x<span class=\"syntax-keyword syntax-operator syntax-arithmetic syntax-c\">+</span><span class=\"syntax-keyword syntax-operator syntax-arithmetic syntax-c\">+</span><span class=\"syntax-punctuation syntax-section syntax-group syntax-end syntax-c\">)</span></span> <span class=\"syntax-meta syntax-block syntax-c\"><span class=\"syntax-punctuation syntax-section syntax-block syntax-begin syntax-c\">{</span>\n    <span class=\"syntax-keyword syntax-operator syntax-c\">*</span>x <span class=\"syntax-keyword syntax-operator syntax-assignment syntax-c\">=</span> <span class=\"syntax-constant syntax-numeric syntax-c\">5</span> <span class=\"syntax-keyword syntax-operator syntax-arithmetic syntax-c\">-</span> <span class=\"syntax-keyword syntax-operator syntax-c\">*</span>x<span class=\"syntax-punctuation syntax-terminator syntax-c\">;</span>\n<span class=\"syntax-punctuation syntax-section syntax-block syntax-end syntax-c\">}</span></span>\n</span></span></code></pre>\n<p>However, I'm not sure how good an idea that is. 😅</p>\n<p>Either way, be careful when you mess with pointers. Making mistakes with memory results in buffer overflows and out-of-bounds writes, which provide significant threats to the security of your code.</p>\n<p><picture class=\"article-picture article-picture-fallback\" style=\"--image-ratio:16 / 9\"><img src=\"https://bd103.dev/blog/2026-10-07-c-for-rust-programmers/vuln-categories-2021.png\" alt=\"A graph visualizing which vulnerability category had the most CVEs between November 2021 and January 2022. Buffer overflow is the third most common, with 346 CVEs, and out-of-bounds writes are the ninth most common, with 204 CVEs. The two categories more common than buffer overflow are denial-of-service with 488 and cross-site scripting with 683.\" loading=\"lazy\" decoding=\"async\" fetchpriority=\"low\" referrerpolicy=\"no-referrer\" class=\"progressive-image\"></picture></p>\n<p>Vulnerability category distribution for CVEs registered between Nov. 2021 and Jan. 2022, <a target=\"_blank\" rel=\"noopener noreferrer\" href=\"https://unit42.paloaltonetworks.com/network-security-trends-cross-site-scripting/\">via</a></p>\n<h2>Conclusion</h2>\n<p>I hope you enjoyed this article! I've honestly had a lot of fun learning C. And while I doubt I'll reach for it for personal projects, it's absolutely a crucial language to know as a systems programmer. All the examples in this blog are <a target=\"_blank\" rel=\"noopener noreferrer\" href=\"https://github.com/BD103/C-for-Rust-Programmers\">available on Github</a>, if you'd like to mess with them yourself!</p>\n<p>Until next time,</p>\n<p>- BD103 :)</p>\n<ol>\n<li>\n<p>Technically you can use <a target=\"_blank\" rel=\"noopener noreferrer\" href=\"https://en.cppreference.com/c/keyword/_Bool\"><code>_Bool</code></a> without the header, but you still need it for the <code>true</code> and <code>false</code> definitions. <a target=\"_blank\" rel=\"noopener noreferrer\" href=\"https://bd103.dev/blog/2026-10-07-c-for-rust-programmers/#fr-_bool-1\">↩</a></p>\n</li>\n<li>\n<p>It looks like <a target=\"_blank\" rel=\"noopener noreferrer\" href=\"https://clang.llvm.org/c_status.html\">Clang still has only partial support for C23</a>, so you may need to wait a little while longer before chucking away your <code>#include &lt;stdbool.h&gt;</code> statements. <a target=\"_blank\" rel=\"noopener noreferrer\" href=\"https://bd103.dev/blog/2026-10-07-c-for-rust-programmers/#fr-c23-1\">↩</a></p>\n</li>\n<li>\n<p>The corresponding Rust function is not idiomatic, and can only correctly handle ASCII text. If I were writing a production version of this function, it would be a single line of code: <code>forward.chars().rev().collect::&lt;String&gt;()</code>. <a target=\"_blank\" rel=\"noopener noreferrer\" href=\"https://bd103.dev/blog/2026-10-07-c-for-rust-programmers/#fr-rust-reverse-string-1\">↩</a></p>\n</li>\n<li>\n<p><a target=\"_blank\" rel=\"noopener noreferrer\" href=\"https://doc.rust-lang.org/stable/std/primitive.usize.html\"><code>usize</code></a> and <a target=\"_blank\" rel=\"noopener noreferrer\" href=\"https://doc.rust-lang.org/stable/std/primitive.isize.html\"><code>isize</code></a> don't perfectly map semantically to <a target=\"_blank\" rel=\"noopener noreferrer\" href=\"https://cppreference.com/c/types/size_t\"><code>size_t</code></a> and <a target=\"_blank\" rel=\"noopener noreferrer\" href=\"https://cppreference.com/c/types/ptrdiff_t\"><code>ptrdiff_t</code></a>. I don't fully understand the difference, however, so I recommend doing your own research before using these types. <a target=\"_blank\" rel=\"noopener noreferrer\" href=\"https://bd103.dev/blog/2026-10-07-c-for-rust-programmers/#fr-size_t-and-ptrdiff_t-1\">↩</a> <a target=\"_blank\" rel=\"noopener noreferrer\" href=\"https://bd103.dev/blog/2026-10-07-c-for-rust-programmers/#fr-size_t-and-ptrdiff_t-2\">↩2</a></p>\n</li>\n<li>\n<p><a target=\"_blank\" rel=\"noopener noreferrer\" href=\"https://shnatsel.github.io/safe-simd-in-rust-even-on-the-inside/\">This blog post on Fearless SIMD</a> provides a great example of using Rust's type system to guarantee the correctness of code. I highly recommend giving it a read! <a target=\"_blank\" rel=\"noopener noreferrer\" href=\"https://bd103.dev/blog/2026-10-07-c-for-rust-programmers/#fr-fearless-simd-1\">↩</a></p>\n</li>\n<li>\n<p>My favorite line of code from that post is <code>100-&gt;a = 0;</code>, it's so cursed! <a target=\"_blank\" rel=\"noopener noreferrer\" href=\"https://bd103.dev/blog/2026-10-07-c-for-rust-programmers/#fr-cursed-arrow-operator-1\">↩</a></p>\n</li>\n</ol>\n",
  "content_markdown": "The very first systems programming language I ever learned was Rust. This is uncommon compared to many other programmers; you're more likely to find someone who learned C or C++ first before coming to Rust. As such, there are plenty of \"Rust for C Programmers\" articles on the internet, but little to no \"C for Rust Programmers\" articles out there.\n\nWell, I'm about to change that! I've been learning C and C++ recently, and *holy cow those languages are quirky*. This blog post is a collection of eyebrow-raising details I learned while teaching myself C. (No C++ today, I'm not ready to dig into that can of worms.) This is not a substitute for a proper C tutorial, you'll need to Google one of those yourself. Rather, it's a list of things to keep in mind when working in the language.\n\nWith the premise set, let's draw the curtain and see what C has to offer!\n\n## Boolean Is Not\\* Built-In\n\nThe original version of C did not have a primitive type for booleans, programs instead used the integers 0 and 1. This was changed in [C99](https://en.wikipedia.org/wiki/C99), which added booleans in the optional [`<stdbool.h>`](https://en.cppreference.com/c/header/stdbool) header [\\[1\\]](https://bd103.dev/blog/2026-10-07-c-for-rust-programmers/#fn-_bool):\n\n```c\n#include <stdbool.h>\n\nint main() {\n    bool yes = true;\n    bool no = false;\n\n    return 0;\n}\n```\n\nEven still, `true` and `false` are not literals or keywords like in other languages. Instead, they are definitions that expand to 1 and 0:\n\n```c\n#define true 1\n#define false 0\n```\n\nThis was changed again in [C23](https://en.wikipedia.org/wiki/C23_\\(C_standard_revision\\))[\\[2\\]](https://bd103.dev/blog/2026-10-07-c-for-rust-programmers/#fn-c23), so now booleans are true language primitives, but if you're compiling for earlier versions you'll need to include `<stdbool.h>`.\n\n## Null-Terminated Strings\n\nA Rust [`&str`](https://doc.rust-lang.org/stable/std/primitive.str.html) is 16 bytes: 8 bytes for the memory address and 8 bytes for the string length. This is because `str` is a dynamically sized type, and uses [pointer metadata](https://bd103.dev/blog/2023-08-06-ptr-metadata/) to track the length of the string.\n\n```rust\n// While a normal reference uses only 8 bytes...\nassert_eq!(std::mem::size_of::<&u8>(), 8);\n\n// ...strings use 16 bytes.\nassert_eq!(std::mem::size_of::<&str>(), 16);\n```\n\nThis approach makes fetching the string length extremely efficient, but requires more memory per `&str` reference. C uses a different approach: it doesn't store the size of its strings separately, but instead terminates every single string with a null byte (`\\0`). This is an intentional trade off that results in a few things:\n\n- C programs don't need to keep track of an extra `size` variable alongside the string\n- Every single string needs room at the end for a null byte\n  - This means empty strings `\"\"` still take up one byte of memory!\n- Null bytes cannot easily be used in the middle of a string without messing up [`<string.h>`](https://cppreference.com/c/header/string)'s functions\n- Forgetting the null terminator can result in out-of-bound reads\n\nIn practice, this requires you to remember to allocate extra space for the null terminator and insert it at the end of strings. For example, here is a program that reverses a string in C:\n\n```c\n 1char* reverse(char* forward) {\n 2    // Calculate the string's length, excluding the null terminator.\n 3    unsigned long len = strlen(forward);\n 4    // Allocate enough room for the string and its null terminator.\n 5    char* reversed = malloc(len + 1);\n 6\n 7    for (int i = 0; i < len; i++) {\n 8        reversed[i] = forward[len - 1 - i];\n 9    }\n10\n11    // Add the null terminator at the end.\n12    reversed[len] = '\\0';\n13\n14    return reversed;\n15}\n```\n\nNote lines 5 and 12, which take special measure to account for the null terminator. For reference, the corresponding Rust function [\\[4\\]](https://bd103.dev/blog/2026-10-07-c-for-rust-programmers/#fn-rust-reverse-string) doesn't need to do so:\n\n```rust\nfn reverse(forward: &[u8]) -> Box<[u8]> {\n    let len = forward.len();\n    let mut reversed = Box::<[u8]>::new_uninit_slice(len);\n\n    for i in 0..len {\n        reversed[i].write(forward[len - 1 - i]);\n    }\n\n    unsafe { reversed.assume_init() }\n}\n```\n\n## Target-Dependent Integer Widths\n\nC's integer types are not guaranteed to use an exact number of bits, instead the width varies depending on the target platform.\n\n| Type        | C Standard       | 64-bit Unix | 64-bit Windows |\n| ----------- | ---------------- | ----------- | -------------- |\n| `char`      | at least 8 bits  | 8 bits      | 8 bits         |\n| `short`     | at least 16 bits | 16 bits     | 16 bits        |\n| `int`       | at least 16 bits | 32 bits     | 32 bits        |\n| `long`      | at least 32 bits | 64 bits     | 32 bits        |\n| `long long` | at least 64 bits | 64 bits     | 64 bits        |\n\nData sourced [via cppreference.com](https://cppreference.com/c/language/arithmetic_types)\n\n`long` being 64 bits on Unix and 32 bits on Windows particularly irks me. I recommend following the advice that [a friend of mine](https://github.com/magicalbat) gave me a few years ago: if you care about cross-platform compatibility, only use the fixed width integers provided by [`<stdint.h>`](https://cppreference.com/c/header/stdint):\n\n| Rust    | C                                                                                                      |\n| ------- | ------------------------------------------------------------------------------------------------------ |\n| `u8`    | `uint8_t`                                                                                              |\n| `u16`   | `uint16_t`                                                                                             |\n| `u32`   | `uint32_t`                                                                                             |\n| `u64`   | `uint64_t`                                                                                             |\n| `usize` | `size_t`[\\[5\\]](https://bd103.dev/blog/2026-10-07-c-for-rust-programmers/#fn-size_t-and-ptrdiff_t)    |\n| `i8`    | `int8_t`                                                                                               |\n| `i16`   | `int16_t`                                                                                              |\n| `i32`   | `int32_t`                                                                                              |\n| `i64`   | `int64_t`                                                                                              |\n| `isize` | `ptrdiff_t`[\\[5\\]](https://bd103.dev/blog/2026-10-07-c-for-rust-programmers/#fn-size_t-and-ptrdiff_t) |\n\n## Error Handling Sucks\n\nI really love Rust's error handling. [`Result`](https://doc.rust-lang.org/stable/std/result/enum.Result.html) forces you to address errors, and sum types (`enum`s) and `match` statements make doing so really easy!\n\nC's error handling story, in comparison, is straight up tragic. It seems to boil down to functions returning a \"magic integer\" like -1 or a null pointer to signal there was an error. You can get a little bit more information by reading [`errno`](https://cppreference.com/c/error/errno), a thread-local integer that can be used to check for specific kinds of errors, but in terms of getting actual error messages and stack traces it is much harder.\n\nWhen writing C, one of the biggest things you'll notice is that the language will never force you to handle errors. It's up to you to remember that functions can fail. For example, here's a snippet of code from [Null-Terminated Strings](https://bd103.dev/blog/2026-10-07-c-for-rust-programmers/#null-terminated-strings):\n\n```c\n// Allocate enough room for the string and its null terminator.\nchar* reversed = malloc(len + 1);\n\nfor (int i = 0; i < len; i++) {\n    reversed[i] = forward[len - 1 - i];\n}\n```\n\nTo new programmers, it's not immediately obvious that [`malloc()`](https://cppreference.com/c/memory/malloc) can fail and return a null pointer. If your machine runs out of memory, `reversed[i]` will cause a segfault upon being accessed. In order to avoid unhelpful segfaults, the program should check for a null pointer and gracefully exit if one is found:\n\n```c\nchar* reversed = malloc(len + 1);\n\nif (reversed == NULL) {\n    perror(\"Error\");\n    exit(1);\n}\n```\n\nDoing so provides a much better experience than a segfault, or worse, other unintentional behavior:\n\n```shellscript\n$ ./main\nError: Cannot allocate memory\n```\n\nOf course, remembering to check every single allocated pointer isn't an amazing developer experience. An approach I played around with was recreating Rust's `Result` in C using tagged unions:\n\n```c\nstruct MallocResult {\n    enum Tag { OK, ERROR } tag;\n    union Value {\n        void* ptr;\n        char* error_message;\n    } value;\n};\n```\n\nIt's a complete mess to use, however, and there's *still* nothing stopping you from immediately accessing `result.value.ptr` without handling the error first. The lack of visibility modifiers like `private` and `public`, which could be used to prevent this, appear to be an intentional design decision. C places full trust in the programmer to *do things right™* and gives few facilities for contracts or safe abstractions.\n\nI personally disagree with this approach. I'm not some mastermind programming wizard who never makes mistakes. I'd much rather encode program requirements into the type system so that the compiler can check them for me\\![\\[6\\]](https://bd103.dev/blog/2026-10-07-c-for-rust-programmers/#fn-fearless-simd) That way, I can be reasonably certain that if the code compiles it was written correctly. But I digress.\n\n## Field Access Syntax\n\nC has two different field access operators: [`.`](https://cppreference.com/c/language/operator_member_access#Member_access) for values and [`->`](https://cppreference.com/c/language/operator_member_access#Member_access_through_pointer) for pointers.\n\n```c\nstruct Foo {\n    int field;\n};\n\nstruct Foo value = { 103 };\nstruct Foo* ptr = &value;\n\n// Accessing the field directly.\nprintf(\"%d\\n\", value.field);\n\n// Accessing the field through a pointer.\nprintf(\"%d\\n\", ptr->field);\n```\n\nThis caught me off guard at first, as Rust uses `.` for everything.\n\n![An old lady holding Frank's Red Hot sauce, except Ferris the crab is photoshopped on top saying 'I put that . on everything'](https://bd103.dev/blog/2026-10-07-c-for-rust-programmers/i-put-that-dot-on-everything.jpg)\n\nIf your curious, [this Stack Overflow write up](https://stackoverflow.com/a/13366168) provides some interesting history on why the `->` operator exists.[\\[7\\]](https://bd103.dev/blog/2026-10-07-c-for-rust-programmers/#fn-cursed-arrow-operator)\n\n## Arrays Become Pointers for Fun\n\nArrays have some weird nuance to them. Sometimes they are plain values with their length accessible using [`sizeof()`](https://cppreference.com/c/language/sizeof), other times they are pointers with an unknown size. In general, this is determined by whether you are handling the array within the function it was defined or not.\n\nTo showcase what I mean, here's a very simple C program that prints the size of two arrays:\n\n```c\nchar declared_size[3] = { 1, 2, 3 };\nchar inferred_size[] = { 4, 5, 6 };\n\nprintf(\"Declared size (main): %ld bytes\\n\", sizeof(declared_size));\nprintf(\"Inferred size (main): %ld bytes\\n\", sizeof(inferred_size));\n```\n\nWhen run, this programs tells you that both arrays take 3 bytes of memory. Good!\n\n```shellscript\n$ ./main\nDeclared size (main): 3 bytes\nInferred size (main): 3 bytes\n```\n\nNow, let's make a slight modification. Let's pass `declared_size` and `inferred_size` through a function before printing its size:\n\n```c\nvoid function(char declared_size[3], char inferred_size[]) {\n    printf(\"Declared size (function): %ld bytes\\n\", sizeof(declared_size));\n    printf(\"Inferred size (function): %ld bytes\\n\", sizeof(inferred_size));\n}\n```\n\nNone of the logic changed, the arrays are identical to the previous example, however now the program reports each array takes **8 bytes of memory**:\n\n```shellscript\n$ ./main\nDeclared size (function): 8 bytes\nInferred size (function): 8 bytes\n```\n\nWhy? Because any array passed through a function is *implicitly converted* to a pointer to the first element. From the C compiler's perspective, the above function actually had the following type signature:\n\n```c\nvoid function(char* declared_size, char* inferred_size);\n```\n\nThis is why it confusingly looked like each array was 8 bytes long. The arrays themselves are 3 bytes, but the pointers take up 8 bytes of memory! Handily, Clang raises a warning when you run `sizeof()` on the pointer form of an array, making it easier to catch this mistake:\n\n```shellscript\n$ clang main.c\n06-arrays/main.c:5:59: warning: sizeof on array function parameter will return size of 'char *'\n      instead of 'char[3]' [-Wsizeof-array-argument]\n    5 |     printf(\"Declared size (function): %ld bytes\\n\", sizeof(declared_size));\n      |                                                           ^\n06-arrays/main.c:4:20: note: declared here\n    4 | void function(char declared_size[3], char inferred_size[]) {\n      |                    ^\n06-arrays/main.c:6:59: warning: sizeof on array function parameter will return size of 'char *'\n      instead of 'char[]' [-Wsizeof-array-argument]\n    6 |     printf(\"Inferred size (function): %ld bytes\\n\", sizeof(inferred_size));\n      |                                                           ^\n06-arrays/main.c:4:43: note: declared here\n    4 | void function(char declared_size[3], char inferred_size[]) {\n      |                                           ^\n2 warnings generated.\n```\n\n## Oh Yeah References Don't Exist\n\nI'd be remiss if I didn't mention it once. C has no borrow checking, and no concept of references. It's all [raw pointers](https://doc.rust-lang.org/stable/std/primitive.pointer.html). This means you can do fun pointer arithmetic like so:\n\n```c\nint array[] = { 0, 1, 2, 3, 4, 5 };\n\n// Woah, iterating over pointers instead of indexes!\nfor (int* x = &array[0]; x < &array[6]; x++) {\n    *x = 5 - *x;\n}\n```\n\nHowever, I'm not sure how good an idea that is. 😅\n\nEither way, be careful when you mess with pointers. Making mistakes with memory results in buffer overflows and out-of-bounds writes, which provide significant threats to the security of your code.\n\n![A graph visualizing which vulnerability category had the most CVEs between November 2021 and January 2022. Buffer overflow is the third most common, with 346 CVEs, and out-of-bounds writes are the ninth most common, with 204 CVEs. The two categories more common than buffer overflow are denial-of-service with 488 and cross-site scripting with 683.](https://bd103.dev/blog/2026-10-07-c-for-rust-programmers/vuln-categories-2021.png)\n\nVulnerability category distribution for CVEs registered between Nov. 2021 and Jan. 2022, [via](https://unit42.paloaltonetworks.com/network-security-trends-cross-site-scripting/)\n\n## Conclusion\n\nI hope you enjoyed this article! I've honestly had a lot of fun learning C. And while I doubt I'll reach for it for personal projects, it's absolutely a crucial language to know as a systems programmer. All the examples in this blog are [available on Github](https://github.com/BD103/C-for-Rust-Programmers), if you'd like to mess with them yourself!\n\nUntil next time,\n\n\\- BD103 :)\n\n1. Technically you can use [`_Bool`](https://en.cppreference.com/c/keyword/_Bool) without the header, but you still need it for the `true` and `false` definitions. [↩](https://bd103.dev/blog/2026-10-07-c-for-rust-programmers/#fr-_bool-1)\n\n2. It looks like [Clang still has only partial support for C23](https://clang.llvm.org/c_status.html), so you may need to wait a little while longer before chucking away your `#include <stdbool.h>` statements. [↩](https://bd103.dev/blog/2026-10-07-c-for-rust-programmers/#fr-c23-1)\n\n3. The corresponding Rust function is not idiomatic, and can only correctly handle ASCII text. If I were writing a production version of this function, it would be a single line of code: `forward.chars().rev().collect::<String>()`. [↩](https://bd103.dev/blog/2026-10-07-c-for-rust-programmers/#fr-rust-reverse-string-1)\n\n4. [`usize`](https://doc.rust-lang.org/stable/std/primitive.usize.html) and [`isize`](https://doc.rust-lang.org/stable/std/primitive.isize.html) don't perfectly map semantically to [`size_t`](https://cppreference.com/c/types/size_t) and [`ptrdiff_t`](https://cppreference.com/c/types/ptrdiff_t). I don't fully understand the difference, however, so I recommend doing your own research before using these types. [↩](https://bd103.dev/blog/2026-10-07-c-for-rust-programmers/#fr-size_t-and-ptrdiff_t-1) [↩2](https://bd103.dev/blog/2026-10-07-c-for-rust-programmers/#fr-size_t-and-ptrdiff_t-2)\n\n5. [This blog post on Fearless SIMD](https://shnatsel.github.io/safe-simd-in-rust-even-on-the-inside/) provides a great example of using Rust's type system to guarantee the correctness of code. I highly recommend giving it a read! [↩](https://bd103.dev/blog/2026-10-07-c-for-rust-programmers/#fr-fearless-simd-1)\n\n6. My favorite line of code from that post is `100->a = 0;`, it's so cursed! [↩](https://bd103.dev/blog/2026-10-07-c-for-rust-programmers/#fr-cursed-arrow-operator-1)\n",
  "dateCreated": "2026-10-09T05:58:27.034165253+00:00",
  "date_created": "2026-10-07T14:30:05+00:00",
  "date_modified": "2026-10-07T14:30:05+00:00",
  "date_published": "2026-10-07T14:30:05+00:00",
  "description": "Comments",
  "external_url": "https://bd103.dev/blog/2026-10-07-c-for-rust-programmers/",
  "git": {
    "commit": "ebb0941c5c06a2ab2377342d607535262a3e969e",
    "path": "items/lobste-rs/2026/10/2026-10-07-c-for-rust-programmers.md",
    "permalink": "https://github.com/aymericbeaumet/aggr-instance/blob/ebb0941c5c06a2ab2377342d607535262a3e969e/items/lobste-rs/2026/10/2026-10-07-c-for-rust-programmers.md"
  },
  "id": "urn:aggr:item:ddde640d64bfcdafde9cf3b1e58dd0513c3adcd4",
  "isBasedOn": {
    "@id": "https://bd103.dev/blog/2026-10-07-c-for-rust-programmers/"
  },
  "mainEntity": {
    "@id": "https://bd103.dev/blog/2026-10-07-c-for-rust-programmers/",
    "@type": "CreativeWork",
    "archivedAt": {
      "@id": "https://aggr.aymericbeaumet.com/items/lobste-rs/2026-10-07-c-for-rust-programmers/#webpage"
    },
    "author": [
      {
        "@type": "Person",
        "name": "bd103.dev by BD103"
      }
    ],
    "dateModified": "2026-10-07T14:30:05+00:00",
    "datePublished": "2026-10-07T14:30:05+00:00",
    "headline": "C for Rust Programmers",
    "timeRequired": "PT9M",
    "url": "https://bd103.dev/blog/2026-10-07-c-for-rust-programmers/",
    "wordCount": 1995
  },
  "name": "Archived snapshot: C for Rust Programmers",
  "preview": null,
  "reading_minutes": 9,
  "replicated_at": null,
  "source": "lobste-rs",
  "source_name": "Lobsters: Top Stories of the Past Week",
  "summary": "Comments",
  "tags": [
    "c",
    "rust"
  ],
  "temporalCoverage": "2026-10-09T05:58:27.034165253+00:00",
  "title": "C for Rust Programmers",
  "url": "https://aggr.aymericbeaumet.com/items/lobste-rs/2026-10-07-c-for-rust-programmers/",
  "word_count": 1995
}