From 6eb73226ec32d3c98d74ceac52a01098dba24402 Mon Sep 17 00:00:00 2001 From: Deyan Rumenov Date: Thu, 30 Oct 2025 22:46:03 +0200 Subject: [PATCH] Suggestions for transcript changes for the C fundamentals course. --- .../0-introduction.txt | 6 +- .../0-introduction.vtt | 6 +- .../1-why-c-is-popular.txt | 8 +- .../1-why-c-is-popular.vtt | 24 ++-- .../10-copying-memory.txt | 22 ++-- .../10-copying-memory.vtt | 36 +++--- .../11-readonly-vs-writable-memory.txt | 10 +- .../11-readonly-vs-writable-memory.vtt | 17 ++- .../12-parsing-http-requests-exercise.txt | 16 +-- .../12-parsing-http-requests-exercise.vtt | 30 ++--- .../2025-06-09-c-fundamentals/13-file-i-o.txt | 8 +- .../2025-06-09-c-fundamentals/13-file-i-o.vtt | 8 +- .../14-file-metadata.txt | 12 +- .../14-file-metadata.vtt | 12 +- .../15-memory-management-in-c.txt | 20 ++-- .../15-memory-management-in-c.vtt | 26 ++--- .../16-stack-vs-heap-memory.txt | 16 +-- .../16-stack-vs-heap-memory.vtt | 20 ++-- .../17-file-i-o-exercise.txt | 42 +++---- .../17-file-i-o-exercise.vtt | 74 ++++++------ .../18-open-socket-listen-for-connections.txt | 6 +- .../18-open-socket-listen-for-connections.vtt | 10 +- .../19-read-write-to-a-socket.txt | 36 +++--- .../19-read-write-to-a-socket.vtt | 52 ++++----- .../2-hello-world-in-c.txt | 26 ++--- .../2-hello-world-in-c.vtt | 40 +++---- .../20-socket-exercise.txt | 68 +++++------ .../20-socket-exercise.vtt | 108 +++++++++--------- .../21-bit-shifts.txt | 10 +- .../21-bit-shifts.vtt | 14 +-- .../22-preprocessor-macros.txt | 30 ++--- .../22-preprocessor-macros.vtt | 58 +++++----- .../23-platform-specific-macros.txt | 30 ++--- .../23-platform-specific-macros.vtt | 44 +++---- .../24-web-server-image-support-exercise.txt | 36 +++--- .../24-web-server-image-support-exercise.vtt | 68 +++++------ .../25-wrapping-up.txt | 20 ++-- .../25-wrapping-up.vtt | 32 +++--- .../3-hello-world-using-printf.txt | 4 +- .../3-hello-world-using-printf.vtt | 6 +- .../4-hello-world-in-c-exercise.txt | 38 +++--- .../4-hello-world-in-c-exercise.vtt | 56 ++++----- .../5-numbers-in-memory.txt | 6 +- .../5-numbers-in-memory.vtt | 6 +- .../6-byte-arrays.txt | 4 +- .../6-byte-arrays.vtt | 4 +- .../7-string-length-null-termination.txt | 10 +- .../7-string-length-null-termination.vtt | 10 +- .../8-strings-memory-exercise.txt | 24 ++-- .../8-strings-memory-exercise.vtt | 30 ++--- .../9-functions-iteration.txt | 44 +++---- .../9-functions-iteration.vtt | 70 ++++++------ 52 files changed, 706 insertions(+), 707 deletions(-) diff --git a/en-US/2025-06-09-c-fundamentals/0-introduction.txt b/en-US/2025-06-09-c-fundamentals/0-introduction.txt index 3777e4e9..bc8e4634 100644 --- a/en-US/2025-06-09-c-fundamentals/0-introduction.txt +++ b/en-US/2025-06-09-c-fundamentals/0-introduction.txt @@ -50,13 +50,13 @@ I mentioned this because this context is relevant for a lot of the design decisi It's not you have somebody who's really dogmatic about their formatting and saying, you must stick to 80 character width as a matter of our formatting configuration. It's no, no, no, 80 characters is literally all you get, and that's it. The physical printer does not go past 80 characters [LAUGH] so that's all you got to work with. [00:04:43] -That type of thing. Also, they had a lot of performance constraints. So the PDP-11 had a whopping 256 kilobytes of memory. It had 1-core single CPU. So no multi-core anything, no parallel processing of any kind. It ran at a blistering 125 kilohertz on that 1-core. So not only was it 110 of a megahertz, not even close to a gigahertz. +That type of thing. Also, they had a lot of performance constraints. So the PDP-11 had a whopping 256 kilobytes of memory. It had 1-core single CPU. So no multi-core anything, no parallel processing of any kind. It ran at a blistering 125 kilohertz on that 1-core. So not only was it 1/10 of a megahertz, not even close to a gigahertz. [00:05:04] So this is essentially the world that they were living in when they designed and developed C. Despite that they were able to build a language that supported building all of these tools that we still use today. Which then leads to the question, if this was the language that they were building for this kind of hardware, why would people still use it on modern hardware when modern hardware runs so much faster? [00:05:26] -Well, one of the things you might notice about all of these pieces of software on the screen here is that they're all things that really, really care about performance. They're things where if you can get something to run acceptably fast on this kind of hardware, imagine what you can do with something that has 3264, gigabytes of memory and 16-core CPU and multiple gigahertz. +Well, one of the things you might notice about all of these pieces of software on the screen here is that they're all things that really, really care about performance. They're things where if you can get something to run acceptably fast on this kind of hardware, imagine what you can do with something that has 32, 64 gigabytes of memory and 16-core CPU and multiple gigahertz. [00:05:47] Yeah, you can get something that runs very, very fast on modern hardware. So fundamentally, what people sort of jokingly, kind of half seriously refer to C as is portable assembly. And assembly language is essentially one very thin layer of abstraction on top of hardware machine instructions that the CPU understands. @@ -100,7 +100,7 @@ And also, finally, C is the language that other languages use to talk to each ot So if you want to do, for example, interop between Node.js and other language, Node.js supports C interop. Haskell, which we talked about earlier, has C interop. Rust has C interop. Pretty much every language has some sort of C interop. Really, one of the only exceptions to this, technically, would have been JavaScript in the browser, which, for a long time, had absolutely no way to talk to C, although now through WebAssembly, that is kind of possible. [00:09:29] -But it's really taken off as this way to have one language talk to another one. If you've got Python embedded in Rust, or something like that. The way that Python and Rust are interacting and talking to each other is using C as an intermediary or at least the C ABI, which is essentially the way that C represents things in memory even if it's not literal.c files. +But it's really taken off as this way to have one language talk to another one. If you've got Python embedded in Rust, or something like that. The way that Python and Rust are interacting and talking to each other is using C as an intermediary or at least the C ABI, which is essentially the way that C represents things in memory even if it's not literal .c files. [00:09:50] diff --git a/en-US/2025-06-09-c-fundamentals/0-introduction.vtt b/en-US/2025-06-09-c-fundamentals/0-introduction.vtt index 688923a5..9a639d51 100644 --- a/en-US/2025-06-09-c-fundamentals/0-introduction.vtt +++ b/en-US/2025-06-09-c-fundamentals/0-introduction.vtt @@ -481,7 +481,7 @@ kilohertz on that 1-core. 102 00:04:59.458 --> 00:05:04.878 -So not only was it 110 of a megahertz, +So not only was it 1/10 of a megahertz, not even close to a gigahertz. 103 @@ -539,7 +539,7 @@ something to run acceptably fast on this 114 00:05:38.300 --> 00:05:43.193 kind of hardware, imagine what you -can do with something that has 3264, +can do with something that has 32, 64 115 00:05:43.193 --> 00:05:47.354 @@ -924,7 +924,7 @@ at least the C ABI, which is essentially 195 00:09:46.308 --> 00:09:50.376 the way that C represents things in -memory even if it's not literal.c files. +memory even if it's not literal .c files. 196 00:09:50.376 --> 00:09:52.986 diff --git a/en-US/2025-06-09-c-fundamentals/1-why-c-is-popular.txt b/en-US/2025-06-09-c-fundamentals/1-why-c-is-popular.txt index e5f615dd..2893d82d 100644 --- a/en-US/2025-06-09-c-fundamentals/1-why-c-is-popular.txt +++ b/en-US/2025-06-09-c-fundamentals/1-why-c-is-popular.txt @@ -8,7 +8,7 @@ And not because it does amazing optimizations, although it does lots of those tw C++ is extraordinarily complicated and the compile times are massively longer than they are for C. So, C is still popular even in a world where C++ exists, even though C++ was designed to be the improvement over C. Because C++ added so much complexity and so much longer compile times that a lot of people are like, yeah, I know C and C++ and I prefer C. [00:01:00] -One really direct example of what C gets you in terms of performance is what I'm gonna call the Local Static HTTP Server Perf Olympics. This is not a real competition. This is very unscientific, and it was done by me very quickly by measuring some different static HTTP servers and just loading up a download of the FrontendMaster's website. +One really direct example of what C gets you in terms of performance is what I'm gonna call the Local Static HTTP Server Performance Olympics. This is not a real competition. This is very unscientific, and it was done by me very quickly by measuring some different static HTTP servers and just loading up a download of the FrontendMaster's website. [00:01:19] And seeing how fast they were able to load it into the browser. Very unscientific, but also a little bit of fun. So in third place with the bronze, we had Node.js. So this is Node's HTTP server package. This has about 2.3 million weekly downloads, it's extremely popular. It's the most popular way to do a static HTTP server in the Node.js ecosystem. @@ -23,7 +23,7 @@ And it is the about 300 lines of C code we write in this workshop with only the It's like, all of these are about under ten milliseconds of response time to like load all the different assets statically. But nevertheless, it is the case that pretty consistently, you can see that even though we're not really like, I didn't sit down and benchmark this, other than this silly little performance Olympics thing. [00:02:28] -I didn't sit down and performance optimize the C thing. These are very mature, well written, well established, designed to be high performance HTTP servers written in Rust. Which has a reputation for Being a very fast language, and Node js, which, granted, has a lot more overhead than rust or C. +I didn't sit down and performance optimize the C thing. These are very mature, well written, well established, designed to be high performance HTTP servers written in Rust. Which has a reputation for being a very fast language, and Node.js, which, granted, has a lot more overhead than Rust or C. [00:02:44] And still, just this example that I just made for this workshop, just by doing some basic bread and butter, just do things the way that kind of C encourages. We're able to get really, really fast performance just because C is just really, really not adding anything, even compared to Rust, yeah. @@ -31,7 +31,7 @@ And still, just this example that I just made for this workshop, just by doing s [00:02:59] >> Speaker 2: Is it Node relying on C++ anyway as well to do that? ->> Richard Feldman: Yeah, so Node, under the hood, certainly the Node runtime is gonna be V8, and V8 is written in C++. It's multiple millions of lines [LAUGH] of C++ code, and billions, it takes forever. But yes, so when you're running your Node HTTP server, you are definitely executing a lot of code that was written in C++, nearly the JavaScript Virtual Machine, V8. +>> Richard Feldman: Yeah, so Node, under the hood, certainly the Node runtime is gonna be V8, and V8 is written in C++. It's multiple millions of lines [LAUGH] of C++ code, and building it takes forever. But yes, so when you're running your Node HTTP server, you are definitely executing a lot of code that was written in C++, namely the JavaScript Virtual Machine, V8. [00:03:24] Yeah, [LAUGH] and nevertheless, [LAUGH] here we are. Cool, I do wanna mention there are some low overhead C alternatives. We're not gonna get into them in this course, but I do wanna at least mention them. So C++, of course, is like definitely the most popular of these, very, very complex. @@ -43,7 +43,7 @@ It's absolutely huge, especially in the game dev space, but not just in game dev Nowhere near C++ levels of popularity, but Zed, like the code editor that I work on at work, Biome, which is the successor to Roam written in Rust. That's like a JavaScript ecosystem thing. Ripgrep, really popular, like grep alternative at the command line. I have a course on FrontendMasters about that if you wanna learn how to do Rust. [00:04:18] -Zig, also very nice language, you might go see the terminal emulator bond in the JavaScript ecosystem, you might've heard of tiger beetle rock. The programming language I'm making is in the process as we speak of rewriting our compiler from rust to Zig. And there's plenty of other, this is like D, Odin, JAI, Carbon, lots of different languages are trying to say, hey, C has so many nice properties, but the ergonomics, there's just some problems with it. +Zig, also very nice language, you might use Ghostty the terminal emulator. Bun in the JavaScript ecosystem, you might've heard of TigerBeetle, Roc, the programming language I'm making is in the process as we speak of rewriting our compiler from Rust to Zig. And there's plenty of others. There's like D, Odin, JAI, Carbon, lots of different languages are trying to say, hey, C has so many nice properties, but the ergonomics, there's just some problems with it. [00:04:43] It doesn't feel like a modern language because it's like half a century old. And people are trying to modernize it, hopefully without sacrificing the things that make it popular in the first place. Okay, all of these low overhead C alternatives definitely support C interop. So, not just languages that are trying to be C alternatives, but also like we said, Node.js and others, really, C interop is almost universal, because C is like the language that other languages use to talk to each other. diff --git a/en-US/2025-06-09-c-fundamentals/1-why-c-is-popular.vtt b/en-US/2025-06-09-c-fundamentals/1-why-c-is-popular.vtt index ef67868e..e202b057 100644 --- a/en-US/2025-06-09-c-fundamentals/1-why-c-is-popular.vtt +++ b/en-US/2025-06-09-c-fundamentals/1-why-c-is-popular.vtt @@ -100,7 +100,7 @@ you in terms of performance is what I'm 21 00:01:05.098 --> 00:01:08.292 gonna call the Local Static -HTTP Server Perf Olympics. +HTTP Server Performance Olympics. 22 00:01:08.292 --> 00:01:09.987 @@ -243,13 +243,13 @@ HTTP servers written in Rust. 51 00:02:39.602 --> 00:02:42.847 -Which has a reputation for Being a very -fast language, and Node js, which, +Which has a reputation for being a very +fast language, and Node.js, which, 52 00:02:42.847 --> 00:02:44.937 granted, has a lot more -overhead than rust or C. +overhead than Rust or C. 53 00:02:44.937 --> 00:02:49.679 @@ -289,7 +289,7 @@ and V8 is written in C++. 60 00:03:11.196 --> 00:03:15.130 It's multiple millions of lines [LAUGH] of -C++ code, and billions, it takes forever. +C++ code, and building it takes forever. 61 00:03:15.130 --> 00:03:19.927 @@ -299,7 +299,7 @@ HTTP server, you are definitely executing 62 00:03:19.927 --> 00:03:24.738 a lot of code that was written in C++, -nearly the JavaScript Virtual Machine, V8. +namely the JavaScript Virtual Machine, V8. 63 00:03:24.738 --> 00:03:30.384 @@ -381,12 +381,12 @@ that if you wanna learn how to do Rust. 79 00:04:18.020 --> 00:04:21.220 Zig, also very nice language, -you might go see the terminal +you might use Ghostty the terminal 80 00:04:21.220 --> 00:04:25.881 -emulator bond in the JavaScript ecosystem, -you might've heard of tiger beetle rock. +emulator. Bun in the JavaScript ecosystem, +you might've heard of TigerBeetle, Roc, 81 00:04:25.881 --> 00:04:30.527 @@ -395,12 +395,12 @@ the process as we speak of rewriting our 82 00:04:30.527 --> 00:04:32.088 -compiler from rust to Zig. +compiler from Rust to Zig. 83 00:04:32.088 --> 00:04:35.659 -And there's plenty of other, -this is like D, Odin, JAI, Carbon, +And there's plenty of others. +There's like D, Odin, JAI, Carbon, 84 00:04:35.659 --> 00:04:40.032 diff --git a/en-US/2025-06-09-c-fundamentals/10-copying-memory.txt b/en-US/2025-06-09-c-fundamentals/10-copying-memory.txt index 2989f10b..4d1f462c 100644 --- a/en-US/2025-06-09-c-fundamentals/10-copying-memory.txt +++ b/en-US/2025-06-09-c-fundamentals/10-copying-memory.txt @@ -1,8 +1,8 @@ [00:00:00] ->> Richard Feldman: The next thing we're gonna do is we're going to write the actual index.html followed by a null terminator after that slash. So if you look up here, we can see, okay, we want to end up with blog followed by /index.html. So we've got our slash here, but we don't have the index html and also we don't have the null terminator there. +>> Richard Feldman: The next thing we're gonna do is we're going to write the actual index.html followed by a null terminator after that slash. So if you look up here, we can see, okay, we want to end up with blog followed by /index.html. So we've got our slash here, but we don't have the index.html and also we don't have the null terminator there. [00:00:17] -Like as this thing continues on, it's got like the ht headers and all that stuff in there. There is no null terminator after the l and html like we want. So we need to actually copy all the bytes for index.html followed by a null byte after this slash right here. +Like as this thing continues on, it's got like the HTTP headers and all that stuff in there. There is no null terminator after the l in html like we want. So we need to actually copy all the bytes for index.html followed by a null byte after this slash right here. [00:00:33] So here's how we're gonna do that. So we're gonna call memcpy, or memcpy, but everybody pronounces it memcpy. This is another C built-in function that comes in the standard library. And I'm gonna pass in end + 1 and then index.html and 11. So let's kind of break down what this is doing. @@ -11,13 +11,13 @@ So here's how we're gonna do that. So we're gonna call memcpy, or memcpy, but ev Basically, so the end + 1, so end is essentially, through all the stuff we've been doing before. We've arranged it so that the memory address of end is this trailing slash that we now have guaranteed to be right here, the + 1 is going to say, okay, move it over one slot after that. [00:01:08] -So now we've got the memory address of whatever comes right after the slash. This is the destination. I don't know why mem copy takes the destination first and then the source, but it does. So basically we're saying, look, start writing the bytes. Copying these bytes to right here. +So now we've got the memory address of whatever comes right after the slash. This is the destination. I don't know why mem copy takes the destination first and then the source, but it does. So basically we're saying, look, start writing the bytes, start copying these bytes to right here. [00:01:22] And then the source thing is index.html, okay. And this is going to basically copy it, basically saying like, take all of the bytes in this memory right here and put them right here. And then 11 is how many bytes we want to copy from the source to the destination. [00:01:41] -So very similarly to the right function, this is once again, a function that's taking three integers. First we have a 64 bit integer which is the address of the destination, and then we have a 64 bit integer which is the address of the source. And then we have how many bytes do you want to copy from the source into the destination? +So very similarly to the write function, this is once again, a function that's taking three integers. First we have a 64 bit integer which is the address of the destination, and then we have a 64 bit integer which is the address of the source. And then we have how many bytes do you want to copy from the source into the destination? [00:01:55] Now if we look at the characters here, index, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10. Why are we passing 11 when there's only 10 bytes in this string? Does anyone know? Why would we pass one more byte to memcpy? And so we wanna copy one more byte than the length of this string, which is, there's 10 bytes here. @@ -32,19 +32,19 @@ I can just copy 11 bytes, and we know that C is going to have null terminated th But here we're actually doing it for justice because this is actually a good idea. Like we actually do want to copy that extra null byte there. And it's a little bit more efficient. If we did put a backslash zero here, it might be a little bit more explicit, but then it's a waste of a byte because then we've got two null bytes back to back when we could just copy in the null byte we've already got, okay. [00:03:12] -So in summary, what this function call is going to do is it's going to take our original string, which now has /blog/ guaranteed whether or not there was a slash there original. And then it's going to copy in this index.html, it's just going to stomp right over the HTTP 1.1 that's right there, followed by the beginning of a header after this. +So in summary, what this function call is going to do is it's going to take our original string, which now has /blog/ guaranteed whether or not there was a slash in the original. And then it's going to copy in this index.html, it's just going to stomp right over the HTTP 1.1 that's right there, followed by the beginning of a header after this. [00:03:30] -So once we've completed this operation, this original request is useless. This is no longer a valid HTTP request. We've just slammed this blog /index.html. Right into the middle of this thing. And then what we're gonna do is return the the initial address there. Of note, one thing we can do to make this like a little bit nicer is we can actually define a variable here called like default file, which is gonna be index.html. +So once we've completed this operation, this original request is useless. This is no longer a valid HTTP request. We've just slammed this /blog/index.html. Right into the middle of this thing. And then what we're gonna do is return the initial address there. Of note, one thing we can do to make this like a little bit nicer is we can actually define a variable here called like default_file, which is gonna be index.html. [00:03:56] -And then we can make it a little bit clearer that we are intentionally doing one more than the length of it because we want the null terminator. And we can do the strlen default file +1 with the understanding that since this is a constant, like this is a string literal, this strlen is just gonna get optimized away anyway. +And then we can make it a little bit clearer that we are intentionally doing one more than the length of it because we want the null terminator. And we can do the strlen default_file + 1 with the understanding that since this is a constant, like this is a string literal, this strlen is just gonna get optimized away anyway. [00:04:11] And this is all going to compile down to just an 11 there anyway. But at least if we write it this way, it's a little bit more obvious that we are intentionally getting one more byte than what's actually in the string's length. Also of note, normally if I were doing this, I wouldn't make this be a local variable like this. [00:04:27] -I would actually just bring it up to the top and say const char star default file equals voila. Const is essentially a special keyword that you use when you're doing things like either at the top level, like. Sort of where the functions are defined. I think you can also do it in line if you want. +I would actually just bring it up to the top and say const char *default_file equals blah, blah. Const is essentially a special keyword that you use when you're doing things like either at the top level, like. Sort of where the functions are defined. I think you can also do it in line if you want. [00:04:44] That basically just says yeah, this is something that I'm not able to mutate these other things I can like start and end. We can mutate them, we can change them as we go along. But this is actually saying, yeah, no, I'm just defining this once, and then it's always gonna be that memory address. @@ -56,19 +56,19 @@ I'm never going to go in and change this. Also there is a convention of if somet Cool, okay, and then the final thing that we're gonna actually do is we're going to return, the actual, start here. But this does, so this is going to like get us back the actual like a blog /index.html that we, that we want here. Now there is a problem here, which is what if the request is too short. [00:05:38] -This is gonna come up in the exercise. So in other words. Let's suppose I'm doing this memcopy and I'm copying into an X509 email right here. But we can see, okay, there's HTTP/1.1. But what if there wasn't that HTTP/1.1? Or what if the string ended right here? There wasn't quite enough space for that L in there, or maybe for the null terminator. +This is gonna come up in the exercise. So in other words. Let's suppose I'm doing this memcopy and I'm copying the index.html right here. But we can see, okay, there's HTTP/1.1. But what if there wasn't that HTTP/1.1? Or what if the string ended right here? There wasn't quite enough space for that L in there, or maybe for the null terminator. [00:05:58] What happens if we get an HTTP request like that? Well, first of all, this shouldn't come up in the wild in theory in the sense that like any browser is just always gonna send you some headers here. So you definitely have some more string to work with. But in practice, that's something that like you really would rather not leave to chance. [00:06:14] -You really don't wanna try to make an assumption about that. And when you have like a third party that's sending you this data, that's how exploits happen. And this is a good example of what we're the approach that we're taking right now. First of all, it's like pretty unusual and it's not what I would do in most program language is even though in c it is like a defensible choice. +You really don't wanna try to make an assumption about that. And when you have like a third party that's sending you this data, that's how exploits happen. And this is a good example of what we're the approach that we're taking right now. First of all, it's like pretty unusual and it's not what I would do in most programming language is even though in C it is like a defensible choice. [00:06:32] But it does have security downsides if I don't explicitly go outta my way to check for that case where I'm doing this memcopy onto. Destination that doesn't have enough sort of bytes, like, semantically for what I'm trying to put here again, C, there's no guardrails here. Like, C is really just gonna be, like, okay, I got three integers. [00:06:51] -I've got, like, here's where I'm gonna write to, here's the memory address that I'm gonna write from, and then here's the number of bytes. If that number of bytes writes off the end of the string, c does not care at all. It's like, yeah, I don't know, whatever memory is there, I'm just gonna stomp all over it. +I've got, like, here's where I'm gonna write to, here's the memory address that I'm gonna write from, and then here's the number of bytes. If that number of bytes writes off the end of the string, C does not care at all. It's like, yeah, I don't know, whatever memory is there, I'm just gonna stomp all over it. [00:07:04] So we really want to make sure to handle that case. We want to explicitly go out of our way to check for this. But this is yet again another example of memory unsafety in C. If we don't remember to or don't think to go out of our way to check for that case and we just write this code as is, this could be an exploit vector. diff --git a/en-US/2025-06-09-c-fundamentals/10-copying-memory.vtt b/en-US/2025-06-09-c-fundamentals/10-copying-memory.vtt index 73899aa7..9e75e68e 100644 --- a/en-US/2025-06-09-c-fundamentals/10-copying-memory.vtt +++ b/en-US/2025-06-09-c-fundamentals/10-copying-memory.vtt @@ -22,7 +22,7 @@ followed by /index.html. 5 00:00:12.696 --> 00:00:15.666 So we've got our slash here, but -we don't have the index html and +we don't have the index.html and 6 00:00:15.666 --> 00:00:17.832 @@ -32,7 +32,7 @@ the null terminator there. 7 00:00:17.832 --> 00:00:20.676 Like as this thing continues on, -it's got like the ht headers and +it's got like the HTTP headers and 8 00:00:20.676 --> 00:00:21.770 @@ -41,7 +41,7 @@ all that stuff in there. 9 00:00:21.770 --> 00:00:25.691 There is no null terminator after -the l and html like we want. +the l in html like we want. 10 00:00:25.691 --> 00:00:28.921 @@ -122,11 +122,11 @@ but it does. 26 00:01:17.258 --> 00:01:20.375 So basically we're saying, -look, start writing the bytes. +look, start writing the bytes, 27 00:01:20.375 --> 00:01:22.375 -Copying these bytes to right here. +Start copying these bytes to right here. 28 00:01:22.375 --> 00:01:26.887 @@ -150,7 +150,7 @@ copy from the source to the destination. 32 00:01:41.419 --> 00:01:44.242 -So very similarly to the right function, +So very similarly to the write function, this is once again, 33 @@ -319,7 +319,7 @@ it's going to take our original string, 68 00:03:17.768 --> 00:03:22.219 which now has /blog/ guaranteed whether or -not there was a slash there original. +not there was a slash in the original. 69 00:03:22.219 --> 00:03:24.659 @@ -347,7 +347,7 @@ This is no longer a valid HTTP request. 74 00:03:36.549 --> 00:03:39.632 -We've just slammed this blog /index.html. +We've just slammed this /blog/index.html. 75 00:03:39.632 --> 00:03:42.014 @@ -356,7 +356,7 @@ Right into the middle of this thing. 76 00:03:42.014 --> 00:03:45.545 And then what we're gonna do is -return the the initial address there. +return the initial address there. 77 00:03:45.545 --> 00:03:50.705 @@ -365,8 +365,8 @@ like a little bit nicer is we can actually 78 00:03:50.705 --> 00:03:56.036 -define a variable here called like default -file, which is gonna be index.html. +define a variable here called like default_file, +which is gonna be index.html. 79 00:03:56.036 --> 00:03:59.303 @@ -380,7 +380,7 @@ because we want the null terminator. 81 00:04:02.269 --> 00:04:06.234 -And we can do the strlen default file +1 +And we can do the strlen default_file + 1 with the understanding that since this 82 @@ -428,8 +428,8 @@ bring it up to the top and 91 00:04:29.899 --> 00:04:32.493 -say const char star -default file equals voila. +say const char *default_file +equals blah, blah. 92 00:04:32.493 --> 00:04:37.083 @@ -541,7 +541,7 @@ So in other words. 115 00:05:40.732 --> 00:05:45.734 Let's suppose I'm doing this memcopy and -I'm copying into an X509 email right here. +I'm copying the index.html right here. 116 00:05:45.734 --> 00:05:49.396 @@ -619,8 +619,8 @@ it's not what I would do in most 132 00:06:28.569 --> 00:06:32.181 -program language is even though in -c it is like a defensible choice. +programming languages is even though in +C it is like a defensible choice. 133 00:06:32.181 --> 00:06:35.454 @@ -660,7 +660,7 @@ then here's the number of bytes. 140 00:06:57.521 --> 00:07:00.638 If that number of bytes writes off the end -of the string, c does not care at all. +of the string, C does not care at all. 141 00:07:00.638 --> 00:07:03.032 diff --git a/en-US/2025-06-09-c-fundamentals/11-readonly-vs-writable-memory.txt b/en-US/2025-06-09-c-fundamentals/11-readonly-vs-writable-memory.txt index 25bcb7a6..c6f6f9a3 100644 --- a/en-US/2025-06-09-c-fundamentals/11-readonly-vs-writable-memory.txt +++ b/en-US/2025-06-09-c-fundamentals/11-readonly-vs-writable-memory.txt @@ -1,8 +1,8 @@ [00:00:00] ->> Richard Feldman: We've now got our const char for the DEFAULT_FILE, which is called index.html. We've got our two path function, which takes in the request and then actually mutates it in place, and then ends up returning it. And then back in main, we have char *req = blah, blah, blah. +>> Richard Feldman: We've now got our const char for the DEFAULT_FILE, which is called index.html. We've got our to_path function, which takes in the request and then actually mutates it in place, and then ends up returning it. And then back in main, we have char *req = blah, blah, blah. [00:00:14] -So then we're gonna call char *path = to path (req), and then this is gonna give us the memory address of that thing. It's gonna do those two for loops that we wrote. It's gonna translate all this back into path.html, this is gonna return the memory address of the beginning of our brand new blog/index.html, which as we know is in the giant global mutable array that is memory. +So then we're gonna call char *path = to_path (req), and then this is gonna give us the memory address of that thing. It's gonna do those two for loops that we wrote. It's gonna translate all this back into path.html, this is gonna return the memory address of the beginning of our brand new blog/index.html, which as we know is in the giant global mutable array that is memory. [00:00:39] It's actually like these bytes right here because we went and just stomped all over this initial request and wrote the index.html right here. And then got back this address right here that's the beginning of this thing which all works totally reasonably, it's just really not what I would do in most languages. @@ -46,13 +46,13 @@ That is a potential reason that they wanna do that is they want to explicitly sa And there was that little gotcha there of the, if you define the function before, sorry, if you call the function before it's defined, you'll get a compiler error. There's two ways to resolve that. Either you can just move it up earlier so that it's defined before it gets called, or you can forward declare it with a semicolon. [00:04:09] -Just write out the type and the name of the function, put a semicolon at the end, either way works. Talked about, two different styles of iteration. We saw the wild loop where we just sort of advancing the memory address of the start and the end of the path. +Just write out the type and the name of the function, put a semicolon at the end, either way works. Talked about, two different styles of iteration. We saw the while loop where we just sort of advancing the memory address of the start and the end of the path. [00:04:21] Talked about copying memory with the memcopy function. So we're just taking some bytes that we got, as long as they're not in the read-only section, and just stomping all over them, just saying, yeah, just here's my source, here's my destination, boom. Just put these bytes over here now. [00:04:33] -And then finally, we talked about read-only memory. So putting all these things together, we were able to take that part of the request and translate it from slash blog in the middle of this like get an HTTP 1.1 all these headers, and get back out the string that we want, which is blog, slash index, dot HTML. +And then finally, we talked about read-only memory. So putting all these things together, we were able to take that part of the request and translate it from slash blog in the middle of this like get and HTTP 1.1 all these headers, and get back out the string that we want, which is blog/index.html. [00:04:51] Whether or not it had a slash at the end of the blog in the first place. Cool, any questions before we get into the exercises. @@ -72,7 +72,7 @@ Whether or not it had a slash at the end of the blog in the first place. Cool, a So this is where the actual type comes into play and makes a difference. So for example, if I said instead of char star, I said int star, what that would affect is that would affect what bracket zero means. So that would mean bracket zero says int is 32 bits, whereas char is eight bits start bracket zero, if start is a char star, means go get me those eight bits and put them right here. [00:05:59] -So give me one byte and put it right here. If I change this to instar and change nothing else about the program, well, first of all, I'd get a compiler error because it would say type mismatch here. I'd have to cast it to instar, but if I cast it to instar, it would still be the same exact integer in memory, this is the bytes of the beginning of that thing. +So give me one byte and put it right here. If I change this to int star and change nothing else about the program, well, first of all, I'd get a compiler error because it would say type mismatch here. I'd have to cast it to int star, but if I cast it to int star, it would still be the same exact integer in memory, this is the bytes of the beginning of that thing. [00:06:15] And that byte the address is exactly the same, no matter whether I'm treating it as a char star, int star, or any other kind of star. The important part here is that the bracket zero is gonna say, either, go get me eight bytes from char star, or if it's int, it's gonna say, go get me 32 bytes. diff --git a/en-US/2025-06-09-c-fundamentals/11-readonly-vs-writable-memory.vtt b/en-US/2025-06-09-c-fundamentals/11-readonly-vs-writable-memory.vtt index e38e2fa0..4124dc0a 100644 --- a/en-US/2025-06-09-c-fundamentals/11-readonly-vs-writable-memory.vtt +++ b/en-US/2025-06-09-c-fundamentals/11-readonly-vs-writable-memory.vtt @@ -11,7 +11,7 @@ which is called index.html. 3 00:00:03.749 --> 00:00:07.169 -We've got our two path function, +We've got our to_path function, which takes in the request and 4 @@ -27,7 +27,7 @@ we have char *req = blah, blah, blah. 6 00:00:14.738 --> 00:00:18.077 So then we're gonna call char -*path = to path (req), and +*path = to_path (req), and 7 00:00:18.077 --> 00:00:21.358 @@ -411,7 +411,7 @@ two different styles of iteration. 87 00:04:14.748 --> 00:04:19.188 -We saw the wild loop where we just sort +We saw the while loop where we just sort of advancing the memory address of 88 @@ -459,12 +459,12 @@ request and translate it from slash blog 97 00:04:43.193 --> 00:04:47.150 in the middle of this like get -an HTTP 1.1 all these headers, and +and HTTP 1.1 all these headers, and 98 00:04:47.150 --> 00:04:51.765 get back out the string that we want, -which is blog, slash index, dot HTML. +which is blog/index.html. 99 00:04:51.765 --> 00:04:56.717 @@ -583,7 +583,7 @@ So give me one byte and put it right here. 123 00:06:01.074 --> 00:06:03.909 -If I change this to instar and change +If I change this to int star and change nothing else about the program, well, 124 @@ -593,9 +593,8 @@ because it would say type mismatch here. 125 00:06:06.943 --> 00:06:11.046 -I'd have to cast it to instar, but -if I cast it to instar, it would still be - +I'd have to cast it to int star, but +if I cast it to int star, it would still be 126 00:06:11.046 --> 00:06:15.707 the same exact integer in memory, this is diff --git a/en-US/2025-06-09-c-fundamentals/12-parsing-http-requests-exercise.txt b/en-US/2025-06-09-c-fundamentals/12-parsing-http-requests-exercise.txt index c6900e63..f4f06a0e 100644 --- a/en-US/2025-06-09-c-fundamentals/12-parsing-http-requests-exercise.txt +++ b/en-US/2025-06-09-c-fundamentals/12-parsing-http-requests-exercise.txt @@ -11,13 +11,13 @@ And they are cache and validation, naming things on off-by-one errors. This is a Here, we have index.html is what we expect, but again, there's this, there's that /index.html. And then finally, this last one we want to be null, but instead it's /blog/index.html. So in this exercise, we're basically gonna be doing some bug fixing. Okay, so this right here might look familiar from the slides, this is exactly the same stuff we're doing there. [00:01:13] -We have char *start and end. We've got our to_path functions taking in the request address, right? The for loop, where we start off at the beginning of the request, we keep going until we hit a space, just start++ along the way. If we encounter a null byte, which we're using the syntax for that, then really return null rather than continuing to read past the end of the string. +We have char *start and end. We've got our to_path functions taking in the request address, right? The for loop, where we start off at the beginning of the request, we keep going until we hit a space, just start++ along the way. If we encounter a null byte, which we're using the bang syntax for that, then we early return null rather than continuing to read past the end of the string. [00:01:31] We skip over the space right there in the GET request, and then we keep going to end begins at start, and then we just keep progressing best there. And then finally, we have this little bit of logic there that's basically saying, okay, if we end in a slash, like we got to get for a /blog/, that's fine, just move the sort of where we're ending back 1 so that we're now on the slash. [00:01:56] -If we didn't have a slash there, then we're gonna write 1 into the original string. And then finally, we do the memcpy, where we're basically overwriting whatever was in the request string originally to get the index.html plus the null terminator. So two things we're gonna do here, one is a little refactor. +If we didn't have a slash there, then we're gonna write one into the original string. And then finally, we do the memcpy, where we're basically overwriting whatever was in the request string originally to get the index.html plus the null terminator. So two things we're gonna do here, one is a little refactor. [00:02:15] So this is not gonna be a bug fix, but it's basically, hey, try refactoring out this +1 by modifying the 'if/else' above. So there's another way you could express this so that the math works out to be the same thing. We're just basically making end be in terms of something else, and that's a totally reasonable way to do it. @@ -60,7 +60,7 @@ So something to be aware of. Okay, so we did that refactor. Now we're going to t So again, no guardrails, if we don't remember to copy over the null terminator, we're just gonna keep reading that memory until we encounter our actual null terminator there. Cool, okay, and then now we come to our actual bug. So these three don't currently trim off the leading slash. [00:06:27] -So what we wanna do is modify to path to fix them. So right now we're saying, okay, GET /blog, HTTP, blah, blah, blah, okay? And what this should be is blog/index.html without the slash in front of it, but when we run the program, it's /blog/index.html. So essentially, again, we have an off-by-one error here. +So what we wanna do is modify to_path to fix them. So right now we're saying, okay, GET /blog, HTTP, blah, blah, blah, okay? And what this should be is blog/index.html without the slash in front of it, but when we run the program, it's /blog/index.html. So essentially, again, we have an off-by-one error here. [00:06:46] So how do we fix this? Well, basically what we wanna do is, we have our sort of start and end here. So the end is where we end up with, I'm sorry, start and end are basically both slashes. So the start is the slash at the beginning here, and then the end is the slash at the end of this thing. @@ -78,14 +78,14 @@ Now, because all we're doing here is we're just looping until we see a space, th But since it's not either of those, this isn't a problem. So the other thing that we could do here is we could combine these two consecutive ++ into a += 2. That would also work exactly the same way. And voila, the bug is now fixed. Cool, so fix that off-by-one error, introduce some others, fix them, great. [00:08:17] -So now, before fixing this now one, we're gonna try moving it up to the beginning of main and see what happens. +So now, before fixing this next one, we're gonna try moving it up to the beginning of main and see what happens. >> Richard Feldman: Okay, so all I did was move it up there. Boom, abort, this is one of our new fun no stack trace errors. We've seen segfault and bus error, and now we're seeing abort. [00:08:36] So what's going on there? And why is it that if I put this code at the end of the file, or sorry, at the end of the function, it works fine. And by the way, if you look at this, this looks like it should be pretty self-contained, right? [00:08:46] -I'm seeing rec4, I've got rec1, rec2, rec3 for the different requests up here, rec4[]=, and then I just call to_path on rec4. This doesn't reference any of the rec1, rec2, or rec3s. All it references is, we're calling this function, we're parsing in this local thing, and we're not using any globals. +I'm seeing req4, I've got req1, req2, req3 for the different requests up here, req4[]=, and then I just call to_path on req4. This doesn't reference any of the req1, req2, or req3s. All it references is, we're calling this function, we're passing in this local thing, and we're not using any globals. [00:09:05] I mean, we're using some string constants, those aren't a problem. So what could possibly be happening [LAUGH] That this thing works? Well, it gets the wrong answer, granted, we wanted to see null here. But it works fine, it runs fine. But then as soon as I move it up to the top of the function, it pulls up the entire program. @@ -108,7 +108,7 @@ I omitted those on purpose in order to cause this error. And so basically, what' So whatever happens to be in memory there, that's what's gonna get stomped on and overwritten. And the reason it behaves differently, if I put it at the end of the function versus earlier, is that whatever happens to be there after those bytes changes depending on whether I'm doing this at the beginning of the function or the end. [00:11:04] -And the reason the program's blowing up is that, up here, when we get to those bytes, the processor or the operating system, it tries to do something when those bytes are overridden that results in some sort of operating system error. So I don't actually know specifically what those bites are doing or what the exact thing is. +And the reason the program's blowing up is that, up here, when we get to those bytes, the processor or the operating system, it tries to do something when those bytes are overridden that results in some sort of operating system error. So I don't actually know specifically what those bytes are doing or what the exact thing is. [00:11:26] You'd have to look at the actual assembly to try to figure that out. But it's probably something along the lines of, remember I mentioned at the very beginning that there was some assembly that we were omitting for the boilerplate of beginning of functions. And the boilerplate is basically stuff like, looking at what the arguments are, getting those out of the global variables into the registers, or storing them, storing where the function's gonna return to and things like that. @@ -129,7 +129,7 @@ When you run this program, okay, I mean, we know that there's a bug here, in tha And this is one of the things that makes memory safety bugs so pernicious, is that in a lot of cases, there's a lot of different factors that go into reproducing it. Another thing I haven't tried, but if you played around with using different compiler optimization settings to build this, compiler optimizations will often rearrange things inside the function in ways that it assumes are harmless, assuming your code is actually doing the right thing. [00:13:23] -Another possibility is that these things could end up with the memory being in such a place that this code works fine, that as soon as you run the optimizer, it blows up. And you might blame the optimizer and say the optimizer must have a bug in it, but it might not. +Another possibility is that these things could end up with the memory being in such a place that this code works fine, then as soon as you run the optimizer, it blows up. And you might blame the optimizer and say the optimizer must have a bug in it, but it might not. [00:13:34] The reason that it might be blowing up is just that the bug was always there. You just weren't happening to see any symptom because the memory it was stomping over happened to be harmless until you kicked in the optimizations, and then it happened to be overriding memory that was not harmless. @@ -155,7 +155,7 @@ And so then if you do that, that can give you more of a clue. Well, first of all Yeah, there's this thing called a stack-smashing attack, which is a whole [LAUGH] Thing that we're not going to get into. But yeah, that is one example of a thing you can do to not prevent the bug, but at least give you a clue of what's actually happening there. [00:15:33] -Okay, yeah, and then the last thing we're gonna do is we're gonna fix this by handling the case where rec is too short to have "index.html" memcop'd into it. Hint, strlen returns an integer whose type is not 'int', but rather 'size_t'. This is a hint, because as you're fixing this, we do actually need to do this, we're going to encounter this compiler error. +Okay, yeah, and then the last thing we're gonna do is we're gonna fix this by handling the case where req is too short to have "index.html" memcop'd into it. Hint, strlen returns an integer whose type is not 'int', but rather 'size_t'. This is a hint, because as you're fixing this, we do actually need to do this, we're going to encounter this compiler error. [00:15:49] So basically, what's happening here is we are saying, okay, I want to detect whether or not we are going to write over this, and if we are going to write over this, then let's blow up instead. So basically we've got our length of the thing that we're copying in and we've got our starting point. diff --git a/en-US/2025-06-09-c-fundamentals/12-parsing-http-requests-exercise.vtt b/en-US/2025-06-09-c-fundamentals/12-parsing-http-requests-exercise.vtt index e1bed498..5b54a834 100644 --- a/en-US/2025-06-09-c-fundamentals/12-parsing-http-requests-exercise.vtt +++ b/en-US/2025-06-09-c-fundamentals/12-parsing-http-requests-exercise.vtt @@ -132,11 +132,11 @@ just start++ along the way. 28 00:01:24.396 --> 00:01:28.264 If we encounter a null byte, which -we're using the syntax for that, then +we're using the bang syntax for that, then 29 00:01:28.264 --> 00:01:31.923 -really return null rather than continuing +we early return null rather than continuing to read past the end of the string. 30 @@ -170,7 +170,7 @@ If we didn't have a slash there, 36 00:01:58.295 --> 00:02:00.483 -then we're gonna write 1 +then we're gonna write one into the original string. 37 @@ -558,7 +558,7 @@ trim off the leading slash. 116 00:06:27.191 --> 00:06:29.833 So what we wanna do is -modify to path to fix them. +modify to_path to fix them. 117 00:06:29.833 --> 00:06:35.458 @@ -717,7 +717,7 @@ introduce some others, fix them, great. 150 00:08:17.824 --> 00:08:19.706 -So now, before fixing this now one, +So now, before fixing this next one, 151 00:08:19.706 --> 00:08:23.550 @@ -763,18 +763,18 @@ pretty self-contained, right? 160 00:08:46.779 --> 00:08:49.975 -I'm seeing rec4, -I've got rec1, rec2, rec3 for +I'm seeing req4, +I've got req1, req2, rej3 for 161 00:08:49.975 --> 00:08:55.017 -the different requests up here, rec4[]=, -and then I just call to_path on rec4. +the different requests up here, req4[]=, +and then I just call to_path on req4. 162 00:08:55.017 --> 00:08:57.782 -This doesn't reference any of the rec1, -rec2, or rec3s. +This doesn't reference any of the req1, +req2, or req3s. 163 00:08:57.782 --> 00:09:01.070 @@ -783,7 +783,7 @@ we're calling this function, 164 00:09:01.070 --> 00:09:05.364 -we're parsing in this local thing, +we're passing in this local thing, and we're not using any globals. 165 @@ -980,7 +980,7 @@ in some sort of operating system error. 205 00:11:21.663 --> 00:11:25.426 So I don't actually know specifically -what those bites are doing or +what those bytes are doing or 206 00:11:25.426 --> 00:11:26.818 @@ -1173,7 +1173,7 @@ could end up with the memory being in such 245 00:13:27.286 --> 00:13:30.519 a place that this code works fine, -that as soon as you run the optimizer, +then as soon as you run the optimizer, 246 00:13:30.519 --> 00:13:31.113 @@ -1380,7 +1380,7 @@ gonna do is we're gonna fix this by 288 00:15:36.463 --> 00:15:39.579 -handling the case where rec is too short +handling the case where req is too short to have "index.html" memcop'd into it. 289 diff --git a/en-US/2025-06-09-c-fundamentals/13-file-i-o.txt b/en-US/2025-06-09-c-fundamentals/13-file-i-o.txt index 00163f01..bf593ac2 100644 --- a/en-US/2025-06-09-c-fundamentals/13-file-i-o.txt +++ b/en-US/2025-06-09-c-fundamentals/13-file-i-o.txt @@ -1,5 +1,5 @@ [00:00:00] ->> Richard Feldman: Now we're going to get into some actual file IO. So up to this point, we've only been working with strings, but of course, in order for our static web server to actually work, we need to be reading these index dot HTML files off of the disk in order to send them back to the browser. +>> Richard Feldman: Now we're going to get into some actual file IO. So up to this point, we've only been working with strings, but of course, in order for our static web server to actually work, we need to be reading these index.html files off of the disk in order to send them back to the browser. [00:00:11] So the browser can do all of its work rendering them and making them look nice. So we're gonna start by looking at how to open a file, and then how to get the size of the file, which is going to be important later. And also reading the contents of the file, of course, something we want to do. @@ -14,13 +14,13 @@ We wanna translate that into the file path of a blog / index.html with or withou If we wanna open that file for reading, which is what we're gonna do in our static web server. We don't care about writing files at all. This is how we would do that. So there's two pieces to note here. So first we're saying we're calling this function named open. [00:01:09] -We're passing in the path and we're giving it this flag that says Read only. This is just a constant that's available for the standard library that basically says, I want to open this file in read-only mode. Other options include, I can say, like, I want to allow writes but not reads. +We're passing in the path and we're giving it this flag that says Read only. This is just a constant that's available from the standard library that basically says, I want to open this file in read-only mode. Other options include, I can say, like, I want to allow writes but not reads. [00:01:24] Or you can say, I want to allow both for our purposes. This is just like a little, nice, little safety measure that we make sure we don't accidentally write to this file, because we really only want to be reading from these. The path again, this is a memory address. [00:01:36] -So as we know, this is an integer that's being passed open, and this also is another integer [LAUGH]. So this flag of whether it's read only or rewrite, etc, is just a constant that's an integer. Now open returns an int, which is known as a file descriptor. Now as we're gonna see in a moment, the file descriptor can also be used to do things like reading things from the file or getting the size of the file. +So as we know, this is an integer that's being passed open, and this also is another integer [LAUGH]. So this flag of whether it's read only or read/write, etc, is just a constant that's an integer. Now open returns an int, which is known as a file descriptor. Now as we're gonna see in a moment, the file descriptor can also be used to do things like reading things from the file or getting the size of the file. [00:02:00] It's basically, a way to avoid having to pass in this path every single time. The operating system has this concept of like, okay, I've opened this file. I've sort of made a little in-memory database of like, yes, this file, this ID, this integer ID, which we call file descriptor or FD for short. @@ -71,7 +71,7 @@ Don't put any other variables in there. Those are all reserved for me, and give It's gonna be just like that first exercise. And we read off the end of Hello World. That's what's gonna happen, if you [LAUGH] printf this thing. It's just whatever ones and zeros happen to be at that address. And what the read function does. It says, okay, give me the file descriptor that you already opened. [00:06:17] -So this is gonna be our example dot txt. And then it says, give me the memory address that you want to read into. So you may recall in our previous session, we did this thing that seemed like a very strange thing to do in most programming languages where we took this request string. +So this is gonna be our example.txt. And then it says, give me the memory address that you want to read into. So you may recall in our previous session, we did this thing that seemed like a very strange thing to do in most programming languages where we took this request string. [00:06:29] There was already some data there, and then we just stomped all over it. It's totally normal thing to do in C. It is such a normal thing to do in C that literally the way that you read files in C is to do exactly that. This is the official C standard library approved way to read files is you literally say, give me a memory address. diff --git a/en-US/2025-06-09-c-fundamentals/13-file-i-o.vtt b/en-US/2025-06-09-c-fundamentals/13-file-i-o.vtt index e94f6e38..df78ffca 100644 --- a/en-US/2025-06-09-c-fundamentals/13-file-i-o.vtt +++ b/en-US/2025-06-09-c-fundamentals/13-file-i-o.vtt @@ -17,7 +17,7 @@ actually work, we need to be reading these 4 00:00:08.528 --> 00:00:11.672 -index dot HTML files off of the disk in +index.html files off of the disk in order to send them back to the browser. 5 @@ -126,7 +126,7 @@ giving it this flag that says Read only. 27 00:01:13.636 --> 00:01:17.895 This is just a constant that's available -for the standard library that basically +from the standard library that basically 28 00:01:17.895 --> 00:01:20.560 @@ -173,7 +173,7 @@ this also is another integer [LAUGH]. 37 00:01:41.138 --> 00:01:45.266 So this flag of whether it's read only or -rewrite, etc, +reed/write, etc, 38 00:01:45.266 --> 00:01:48.111 @@ -606,7 +606,7 @@ descriptor that you already opened. 129 00:06:17.708 --> 00:06:19.921 -So this is gonna be our example dot txt. +So this is gonna be our example.txt. 130 00:06:19.921 --> 00:06:23.108 diff --git a/en-US/2025-06-09-c-fundamentals/14-file-metadata.txt b/en-US/2025-06-09-c-fundamentals/14-file-metadata.txt index 0fd7ef77..0fd67d6f 100644 --- a/en-US/2025-06-09-c-fundamentals/14-file-metadata.txt +++ b/en-US/2025-06-09-c-fundamentals/14-file-metadata.txt @@ -11,10 +11,10 @@ And then three I can call read passing that buffer and then it'll just read that So a struct, you can kind of think about it like an object in other languages, but a very, very bare bones, very, very minimal object. Really what a struct is in C is, it's maybe more similar to imagine if you just had all these variables one after the other and they were all just contiguously stored back to back in memory. [00:01:05] -They're not quite contiguous. There's this thing called alignment padding, but we're not gonna get into alignment in this workshop. But the basic idea here is that there's no extra metadata here at all. So in some languages you can do stuff like, I can iterate over all the fields and they'll give them the strings. +They're not quite contiguous. There's this thing called alignment padding, but we're not gonna get into alignment in this workshop. But the basic idea here is that there's no extra metadata here at all. So in some languages you can do stuff like, I can iterate over all the fields and they'll give them as strings. [00:01:20] -These strings are gone, C is I don't know, forget about that, we're just throwing those out the window. These are just conveniences for the programmer so that it knows that this string means get the first one and this string means get the second one. So if you say start.mode_t, it's, that means get the memory at this offset. +These strings are gone, C is I don't know, forget about that, we're just throwing those out the window. These are just conveniences for the programmer so that it knows that this string means get the first one and this string means get the second one. So if you say stat.mode_t, it's, that means get the memory at this offset. [00:01:36] So this is all just one big contiguous chunk of bytes. And in fact, if you wanted to you could try to get access to these different fields on this struct by just taking the memory address of your particular stat instance and just doing the same thing we've been doing with these arrays. @@ -26,7 +26,7 @@ Just like +5, +6, whatever, just add to it and just read the memory at that addr So it's essentially a convenience for what we're doing. Now we're gonna call this C function in a second, that's going to give us back a stat instance. So it's basically gonna give us one of these values. And then what we're gonna do is we're gonna get the thing that we care about, which is this, st_size, which is the total size in bytes of the file. [00:02:41] -Now you might notice the entire struct stat is way more information than just the total size in bytes. This is 144 bytes worth of data, and it's got all sorts of stuff like the inode number, in case you hear that, the user ID of the owner, the group ID, the device ID, last access time, last modification time, all this stuff. +Now you might notice the entire struct stat is way more information than just the total size in bytes. This is 144 bytes worth of data, and it's got all sorts of stuff like the inode number, in case you need that, the user ID of the owner, the group ID, the device ID, last access time, last modification time, all this stuff. [00:02:58] There's all this information about the metadata of the file. And when we do this one function call, it just gives us back that one thing, this whole struct even though all we care about is just this one thing. So here's how we're gonna do that. We're gonna say struct stat metadata. @@ -35,7 +35,7 @@ There's all this information about the metadata of the file. And when we do this The struct keyword is essentially kind of int or char or something like that, except that it's saying this isn't one of the built-in types, this is actually a user-defined struct type. And then the next thing you say is the name of the struct. So struct followed by stat. [00:03:32] -So stat is the name of the struct that this is gonna be. And we say metadata, once again, we are actually not initializing this memory. So we're not doing an equals. You remember previously, we said, I wanna make this buffer, and I said, (100); which basically means I want you to reserve, this is gonna be an address, and I want you to reserve that many bytes, 100 bytes of memory. +So stat is the name of the struct that this is gonna be. And we say metadata, once again, we are actually not initializing this memory. So we're not doing an equals. You remember previously, we said, I wanna make this buffer, and I said, [100]; which basically means I want you to reserve, this is gonna be an address, and I want you to reserve that many bytes, 100 bytes of memory. [00:03:55] Don't put other stuff in there, because I'm gonna write into this. This is exactly the same thing, except instead of 100 bytes its the 144 bytes that this thing takes up automatically. So the compiler is gonna take care of that for you. But basically, when you get to this program, if you were to look at the assembly language, basically what it's gonna be doing is saying, essentially, reserve 144 bytes worth of stuff, and then just give me back the address to the beginning of that, and I'm gonna write into that. @@ -44,7 +44,7 @@ Don't put other stuff in there, because I'm gonna write into this. This is exact And just like with read, essentially you call this function called fstat, which basically is fd, I'll talk about the ampersand in a second here, and then metadata. And it's basically gonna be, okay cool, give me the file descriptor, give me the address to write into, and it's just gonna go ahead and write 144 bytes into that memory that contains all of this metadata information about the file. [00:04:42] -So after we have run this, now I can go look at my metadata thing and say, .this.that, get the values off of it. But until I've actually called that fstat, I have not populated this metadata thing, and this is just memory garbage. Again, I could say metadata., whatever, st_rdev, whatever, and that's just gonna give me back a couple of bytes of memory garbage, whatever happens to be a memory until I've actually called fstat on it. +So after we have run this, now I can go look at my metadata thing and say, .this, .that, get the values off of it. But until I've actually called that fstat, I have not populated this metadata thing, and this is just memory garbage. Again, I could say metadata., whatever, st_rdev, whatever, and that's just gonna give me back a couple of bytes of memory garbage, whatever happens to be a memory until I've actually called fstat on it. [00:05:06] Once again, it returns -1 if it fails. So once again, this is where we do the error handling. This time I did a little, because we're actually not using the output of fstat at all, the return value is only used for error handling, which is also a common thing we see in C. @@ -83,5 +83,5 @@ We know how much memory to reserve, so that when we do our read, we're actually Not quite. [LAUGH] It's a little bit of an extra dance, a little bit of a stomping over memory with other memory, uninitialized memory, that kind of stuff. But the reason we're going through this process is just to give you a sense of this is how things are done in C. [00:08:27] -And also worth noting, this is also quite efficient, and when we get to the section on heat memory, we can see how the thing that's more convenient is in many ways less efficient than doing it this way. +And also worth noting, this is also quite efficient, and when we get to the section on heap memory, we can see how the thing that's more convenient is in many ways less efficient than doing it this way. diff --git a/en-US/2025-06-09-c-fundamentals/14-file-metadata.vtt b/en-US/2025-06-09-c-fundamentals/14-file-metadata.vtt index c5b5d81e..1a77c026 100644 --- a/en-US/2025-06-09-c-fundamentals/14-file-metadata.vtt +++ b/en-US/2025-06-09-c-fundamentals/14-file-metadata.vtt @@ -134,7 +134,7 @@ you can do stuff like, 28 00:01:17.187 --> 00:01:20.039 I can iterate over all the fields and -they'll give them the strings. +they'll give them as strings. 29 00:01:20.039 --> 00:01:21.005 @@ -157,7 +157,7 @@ this string means get the second one. 33 00:01:30.344 --> 00:01:36.066 -So if you say start.mode_t, it's, +So if you say stat.mode_t, it's, that means get the memory at this offset. 34 @@ -260,7 +260,7 @@ it's got all sorts of stuff like the inode 54 00:02:51.748 --> 00:02:55.149 -number, in case you hear that, +number, in case you need that, the user ID of the owner, the group ID, 55 @@ -336,7 +336,7 @@ I wanna make this buffer, and I said, 70 00:03:45.565 --> 00:03:51.115 -(100); which basically means I want you +[100]; which basically means I want you to reserve, this is gonna be an address, 71 @@ -419,7 +419,7 @@ now I can go look at my metadata thing and 87 00:04:46.121 --> 00:04:48.968 -say, .this.that, get the values off of it. +say, .this, .that, get the values off of it. 88 00:04:48.968 --> 00:04:53.293 @@ -749,7 +749,7 @@ this is also quite efficient, 156 00:08:30.675 --> 00:08:34.771 -and when we get to the section on heat +and when we get to the section on heap memory, we can see how the thing that's 157 diff --git a/en-US/2025-06-09-c-fundamentals/15-memory-management-in-c.txt b/en-US/2025-06-09-c-fundamentals/15-memory-management-in-c.txt index 535f0637..fec2f41b 100644 --- a/en-US/2025-06-09-c-fundamentals/15-memory-management-in-c.txt +++ b/en-US/2025-06-09-c-fundamentals/15-memory-management-in-c.txt @@ -1,5 +1,5 @@ [00:00:00] ->> Richard Feldman: One other question you might have is, well, hey, how come fstat doesn't just return the stack stat struct? Why do we have to pass it in like this, when it could have instead just said, well, now fstat is going to return the stat struct, just give me back, all those things. +>> Richard Feldman: One other question you might have is, well, hey, how come fstat doesn't just return the stat struct? Why do we have to pass it in like this, when it could have instead just said, well, now fstat is going to return the stat struct, just give me back, all those things. [00:00:15] Well, the short answer is that, if you were to return the stat struct, that means that you have to return all 144 bytes every single time you do that. So if the caller wants to return that, they now have to copy all 144 bytes again. So in other words, if I have my function that's read the files exact bytes or whatever, and I call that, I call fstat, fstat gives me back those 144 bytes. @@ -35,7 +35,7 @@ All of the memory for the variable that functions just automatically gets freed. It's like, no, no, that's not how functions work. They just automatically, sort of magically, have automatic memory management, not with the garbage collector, but just by virtue of how functions work. You call them, and then you don't have to ever think about all the variables you've allocated locally. [00:03:35] -That memory just is gone as soon as the function itself is gone, which is good, because otherwise calling functions would leak memory. [LAUGH] Unless you explicitly freeze stuff. But this does mean that it's totally unsafe and also totally allowed, at least the C, to return addresses that are defined inside the function body. +That memory just is gone as soon as the function itself is gone, which is good, because otherwise calling functions would leak memory. [LAUGH] Unless you explicitly freed stuff. But this does mean that it's totally unsafe and also totally allowed, at least in C, to return addresses that are defined inside the function body. [00:03:52] So if you have an int or something like that in the middle of your function, you can return that int 'cause it's gonna copy the four bytes in the return value. But if you return the address to that int, well, now you're in dangerous territory, because if the caller after that function has finished and has returned, if the caller holds onto that address and says, I think I'll go see what's in that memory right now. @@ -47,13 +47,13 @@ It might or might not be what it was the last time the function ran, and now we' When you return the address to something in the middle of a function, basically you are returning an address to memory that might get totally overwritten the next time some other function calls. Because from the operating system's perspective and from the running program's perspective, that function exited that memory is fair game. [00:04:47] -Anybody is free to write whatever they want into that memory. Anytime you call another function, it's free to stop all over it, and it's too late to do anything about it because the function has exited. So if you do this, you're basically just asking for trouble. So yeah, we could return a stat address. +Anybody is free to write whatever they want into that memory. Anytime you call another function, it's free to stomp all over it, and it's too late to do anything about it because the function has exited. So if you do this, you're basically just asking for trouble. So yeah, we could return a stat address. [00:05:04] But if we did that, we would basically be saying, cool, now we're returning an address to some memory that has been marked as free and considered fair game. And so as you're reading your stat struct, you might say, this all works very well. And you refactor your code a little bit to call another function and suddenly instead of getting the nice, correct stat values, you're getting total memory garbage, because that other function just stomped all over it. [00:05:28] -Because as far as the program was concerned, that function had exited and that memory was fair game. You may recall that when we had this function to path that we wrote in the previous section, we took in this request, and we were cool. I'm gonna take in this request and then I'm going to return an address of the actual path and that path is going to be different. +Because as far as the program was concerned, that function had exited and that memory was fair game. You may recall that when we had this function to_path that we wrote in the previous section, we took in this request, and we were cool. I'm gonna take in this request and then I'm going to return an address of the actual path and that path is going to be different. [00:05:48] And you may recall that it might've seemed a little bit strange that we were going to all this trouble to stomp all over that request memory. Well, one of the reasons that we did that is that, believe it or not, that's actually the safer option. [LAUGH] Because the caller actually is responsible for that request memory. @@ -74,7 +74,7 @@ Which in practice it always should be, but we do have to be careful in case we'r Now granted, if the caller is allocating this in the middle of the caller's body, then the caller has to make sure on their end, not to accidentally return this path without, I don't know, copying it somewhere else or something like that. But, yeah, this is essentially why we did that in that way. [00:07:26] -Cool, yeah, so this is an address into an arguments, memory, not into a local variables, memory. That's why that worked. Okay, now this is where we're gonna get into the heap. So functions can reserve long lived memory chunks using malloc there are other ways to do this. Malloc is actually a wrapper around mmap or virtual alloc on Windows, which we're not gonna get into. +Cool, yeah, so this is an address into an argument's memory, not into a local variable's memory. That's why that worked. Okay, now this is where we're gonna get into the heap. So functions can reserve long lived memory chunks using malloc there are other ways to do this. Malloc is actually a wrapper around mmap or virtual alloc on Windows, which we're not gonna get into. [00:07:45] But for all intents and purposes, malloc, which is how most people pronounce it, even though it's short for malloc, like memory allocate. This is a super common function that you will see used all the time. It is less performant than what we're using. What we've been using so far, it is not strictly necessary. @@ -83,13 +83,13 @@ But for all intents and purposes, malloc, which is how most people pronounce it, And in fact, the final version of this web server that we've got does not use malloc at all. One of the coolest pieces of advice I got about programming in C and I guess low level programming in general, is you don't always need to do this. In fact, in many cases, you don't need to do this at all. [00:08:19] -And if you try to think carefully about ways to avoid doing malloc by instead doing tricks like what we did in the previous section, where we stopping over some memory that does need to be used. You can actually end up with programs that are believe it or not, less error-prone andin many cases and also run faster as a bonus. +And if you try to think carefully about ways to avoid doing malloc by instead doing tricks like what we did in the previous section, where we stopping over some memory that doesn't need to be used. You can actually end up with programs that are believe it or not, less error-prone in many cases and also run faster as a bonus. [00:08:35] But having said that, it's important to understand what malloc does. So we're gonna go through it even though it's not what we're gonna end up using In the final version of this and to sort of understand like what its trade-offs are. So basically when you call malloc, you can basically say, hey, I want to reserve a long-lived chunk of memory. [00:08:50] -This is not gonna end when the function ends. This is just gonna be hanging out there and we're gonna make sure that that memory doesn't get touched, doesn't get stomped over when the function ends. And when you call malloc, it's gonna return Return and address that memory, which you can then continue using even after this function returns. +This is not gonna end when the function ends. This is just gonna be hanging out there and we're gonna make sure that that memory doesn't get touched, doesn't get stomped over when the function ends. And when you call malloc, it's gonna return return an address to that memory, which you can then continue using even after this function returns. [00:09:05] However, there's the downside. So by default, every time you call malloc, you have a memory leak. When you call malloc, it's saying, yeah, it's long lived. And when does that life end? When does that memory get freed and get returned back to be potentially used for other things? @@ -119,16 +119,16 @@ Whatever ones and zeros somebody else later on automatically got written into th [LAUGH] So essentially, what happens on a double free is you're coming along like, hey, I'm done with this memory. Great, no problem. I call free on it, and I never use that variable ever again. I never try to read from it, but I do actually hold onto that address, and although I don't read from it, I do call free on it later again. [00:11:36] -So that's a double free. I freed the same address twice. The problem with that is, if somebody in between the first free and the second free called malloc. It's entirely possible that Malik gave out that same address from earlier again and said, here you go, here's the address. +So that's a double free. I freed the same address twice. The problem with that is, if somebody in between the first free and the second free called malloc. It's entirely possible that malloc gave out that same address from earlier again and said, here you go, here's the address. [00:11:49] So when I call free a second time, the double free, I'm potentially freeing somebody else's allocation, [LAUGH] some other valid allocation. So this, when I say it's like potentially even worse than a use after free, The way that it can be worse is that the symptom might be somewhere totally like distant from the double free. [00:12:04] -The second call to free itself is like totally harmless. And then all of a sudden this totally seemingly unrelated code is just like getting memory garbage. And you're like, what? What's going on here? Is there a use after free? And you look at how that allocation's used and you're like, no, I'm calling mallocing, right? +The second call to free itself is like totally harmless. And then all of a sudden this totally seemingly unrelated code is just like getting memory garbage. And you're like, what? What's going on here? Is there a use after free? And you look at how that allocation's used and you're like, no, I'm calling malloc, right? [00:12:16] -I'm never freeing it. I'm never using it. I don't understand what's going on. And the problem actually, is that some totally unrelated code was holding on to an address and freed it. Total nightmare. So if you can avoid using malloc and free, on the one hand, you might get a new set of problems, such as we saw earlier where like you're stomping all over memory and you have to be careful not to stomp too far. +I'm never freeing it. I'm never using it. I don't understand what's going on. And the problem actually, is that some totally unrelated code was holding on to that address and freed it. Total nightmare. So if you can avoid using malloc and free, on the one hand, you might get a new set of problems, such as we saw earlier where like you're stomping all over memory and you have to be careful not to stomp too far. [00:12:35] But on the other hand, it means that you don't have to worry about these lifetime issues anymore. You don't have to get it exactly right. Call free exactly the right number of times you can just sort of avoid that whole category of problems. diff --git a/en-US/2025-06-09-c-fundamentals/15-memory-management-in-c.vtt b/en-US/2025-06-09-c-fundamentals/15-memory-management-in-c.vtt index 7c55ebb1..85801c5a 100644 --- a/en-US/2025-06-09-c-fundamentals/15-memory-management-in-c.vtt +++ b/en-US/2025-06-09-c-fundamentals/15-memory-management-in-c.vtt @@ -8,7 +8,7 @@ well, hey, 2 00:00:02.394 --> 00:00:05.105 how come fstat doesn't just -return the stack stat struct? +return the stat struct? 3 00:00:05.105 --> 00:00:09.716 @@ -326,7 +326,7 @@ functions would leak memory. 68 00:03:40.328 --> 00:03:43.698 [LAUGH] Unless you -explicitly freeze stuff. +explicitly freed stuff. 69 00:03:43.698 --> 00:03:48.018 @@ -335,7 +335,7 @@ unsafe and also totally allowed, 70 00:03:48.018 --> 00:03:52.844 -at least the C, to return addresses that +at least in C, to return addresses that are defined inside the function body. 71 @@ -424,7 +424,7 @@ they want into that memory. 88 00:04:50.327 --> 00:04:53.841 Anytime you call another function, -it's free to stop all over it, and +it's free to stomp all over it, and 89 00:04:53.841 --> 00:04:57.372 @@ -482,7 +482,7 @@ that memory was fair game. 100 00:05:32.836 --> 00:05:37.021 You may recall that when we had this -function to path that we wrote in +function to_path that we wrote in 101 00:05:37.021 --> 00:05:41.224 @@ -638,11 +638,11 @@ why we did that in that way. 132 00:07:26.053 --> 00:07:28.465 Cool, yeah, so this is an address -into an arguments, memory, +into an argument's memory, 133 00:07:28.465 --> 00:07:29.908 -not into a local variables, memory. +not into a local variable's memory. 134 00:07:29.908 --> 00:07:32.051 @@ -733,7 +733,7 @@ did in the previous section, 152 00:08:25.641 --> 00:08:28.552 where we stopping over some -memory that does need to be used. +memory that doesn't need to be used. 153 00:08:28.552 --> 00:08:31.924 @@ -742,7 +742,7 @@ programs that are believe it or not, 154 00:08:31.924 --> 00:08:35.432 -less error-prone andin many cases and +less error-prone in many cases and also run faster as a bonus. 155 @@ -788,7 +788,7 @@ stomped over when the function ends. 163 00:08:58.739 --> 00:09:02.237 And when you call malloc, it's gonna -return Return and address that memory, +return return an address to that memory, 164 00:09:02.237 --> 00:09:05.319 @@ -1068,7 +1068,7 @@ the second free called malloc. 223 00:11:43.722 --> 00:11:47.242 -It's entirely possible that Malik gave out +It's entirely possible that malloc gave out that same address from earlier again and 224 @@ -1132,7 +1132,7 @@ used and you're like, no, 237 00:12:15.671 --> 00:12:16.947 -I'm calling mallocing, right? +I'm calling malloc, right? 238 00:12:16.947 --> 00:12:17.587 @@ -1153,7 +1153,7 @@ And the problem actually, 242 00:12:20.963 --> 00:12:23.947 is that some totally unrelated code was -holding on to an address and freed it. +holding on to that address and freed it. 243 00:12:23.947 --> 00:12:24.684 diff --git a/en-US/2025-06-09-c-fundamentals/16-stack-vs-heap-memory.txt b/en-US/2025-06-09-c-fundamentals/16-stack-vs-heap-memory.txt index 716660c1..16ce8589 100644 --- a/en-US/2025-06-09-c-fundamentals/16-stack-vs-heap-memory.txt +++ b/en-US/2025-06-09-c-fundamentals/16-stack-vs-heap-memory.txt @@ -1,5 +1,5 @@ [00:00:00] ->> Richard Feldman: Bring all that together, we've got our thing back here, we've got our struct stat metadata. We're calling fstat and the file descriptor, metadata address. We asked, what if I wanna read all the bytes? This is the answer to that question. So now that I've got my metadata populated, instead of saying char buffer bracket 100, I can say char buffer metadata.st_size. +>> Richard Feldman: Bring all that together, we've got our thing back here, we've got our struct stat metadata. We're calling fstat on the file descriptor, metadata address. We asked, what if I wanna read all the bytes? This is the answer to that question. So now that I've got my metadata populated, instead of saying char buffer[100], I can say char buffer[metadata.st_size]. [00:00:18] And this will basically say, now my buffer is, instead of being hard-coded at 100, it's going to reserve, again, in the functions memory, however many bytes that file size is. But unfortunately, this can very easily lead to a segmentation fault if we don't [LAUGH] double up on that, right? @@ -35,10 +35,10 @@ And then, I need to remember, just like I remember the file descriptor, not only It doesn't matter, it's just I need to remember to do the sort of bookkeeping myself manually. Now, worth noting [LAUGH] that another thing that can happen is, remember I mentioned earlier that read says, tell me the most bytes to read, and then it returns how many bytes I actually read. [00:03:17] -Now, I think that can also happen is, yeah, it can potentially say, look, if you give me a number that's too big, I'm just not gonna do that for you, I'm not gonna read that many bytes. So I actually experimented with this and found that if I asked, say, hey, read five gigabytes out of this file in a single read call. +Now, a think that can also happen is, yeah, it can potentially say, look, if you give me a number that's too big, I'm just not gonna do that for you, I'm not gonna read that many bytes. So I actually experimented with this and found that if I asked, say, hey, read five gigabytes out of this file in a single read call. [00:03:34] -Nock was like, nah, nah, nah, that's too many gigabytes, dial it down a little bit, that's that's too much. So the fix for this is that you read in multiple chunks. So instead of saying, I'm just gonna pass in, just read the entire thing. What you do is, you pick a chunk size that's smaller than that, and you essentially read one chunk at a time into your buffer, and then you can sort of deal with that in chunks. +MacOS was like, nah, nah, nah, that's too many gigabytes, dial it down a little bit, that's that's too much. So the fix for this is that you read in multiple chunks. So instead of saying, I'm just gonna pass in, just read the entire thing. What you do is, you pick a chunk size that's smaller than that, and you essentially read one chunk at a time into your buffer, and then you can sort of deal with that in chunks. [00:03:58] And this is sort of the best practice if you're working with this in a production setting. Now, a lot of programming languages will paper over this. Of course, they're all calling read under the hood, and sometimes they'll offer you a read chunks function. Or sometimes, they'll just be like, yeah, I'll just do the chunks thing automatically for you kind of behind the scenes, and just build up a really big buffer usually using a malloc hook equivalent on the heap, just for you. @@ -56,16 +56,16 @@ Why not, indeed? And this is also a very common pattern that you will see, is wh It's actually quite common to say, hey, I'm just gonna allocate on the stack exactly the memory that I need, because I don't need to read the entire thing at a time, I just need to know how big the file is so I know kind of when to stop. [00:05:20] -Even better, this is gonna have better performance. And also, now there's no need to remember to call free later because we're only dealing with stack memory. We do need to grant to deal with the complexity of reading in chunks, but it turns out, we need to do that, anyway, if we wanna support actually reading very large files. +Even better, this is gonna have better performance. And also, now there's no need to remember to call free later because we're only dealing with stack memory. We do need to, granted, deal with the complexity of reading in chunks, but it turns out, we need to do that, anyway, if we wanna support actually reading very large files. [00:05:35] -Okay, so, to summarize all the things we talked about. We started out with opening a file and then remembering to close it later, very important. Getting its size by using the Fstat, and then we talked about structs and how those get populated, and all the API considerations around that. +Okay, so, to summarize all the things we talked about. We started out with opening a file and then remembering to close it later, very important. Getting its size by using the fstat, and then we talked about structs and how those get populated, and all the API considerations around that. [00:05:50] -Talked about reading the contents of the file into an actual buffer, and how we can't do reads that are too big. So, although it might make sense theoretically, to do a malloc so we can just skip the exact size, and not worry about overflowing the stack. Actually, in practice, we end up probably wanting to do a chunked read, anyway, because the operating system will otherwise give us an error. +Talked about reading the contents of the file into an actual buffer, and how we can't do reads that are too big. So, although it might make sense theoretically, to do a malloc so we can just get the exact size, and not worry about overflowing the stack. Actually, in practice, we end up probably wanting to do a chunked read, anyway, because the operating system will otherwise give us an error. [00:06:09] -And then, finally, we talked about stack vs heap, and sort of the trade offs there. Stack, you don't have to worry about managing lifetimes, remember when you call free. But the heap is much, much bigger, and although there's some ergonomic benefits, there are some performance downsides. Number one, malloc and free are definitely considerably slower than using the stack. +And then, finally, we talked about stack vs heap, and sort of the trade offs there. Stack, you don't have to worry about managing lifetimes, remembering when to call free. But the heap is much, much bigger, and although there's some ergonomic benefits, there are some performance downsides. Number one, malloc and free are definitely considerably slower than using the stack. [00:06:25] And also there are some correctness downsides, where if you call free at the wrong time, it's not just that you might get a memory leak if you forget to do it, but also if you call it too soon, you get a use after free, which is really bad. @@ -97,7 +97,7 @@ You could pick any name you want here, you can define your own structs also. So And then you write all of the fields and choose the names for them. Cool, other questions? >> Richard Feldman: Yeah. >> Student: What do you think about memory arenas? ->> Richard Feldman: Yeah, great. Memory arenas are basically an alternative to malloc and free, where you essentially, how do I explain this concisely? So I guess it would be like, if inside of two path we passed a third argument that was basically the memory address to, it's almost like you're making a little custom stack of your own [LAUGH] that can kind of like, you can just kind of allocate some memory into. +>> Richard Feldman: Yeah, great. Memory arenas are basically an alternative to malloc and free, where you essentially, how do I explain this concisely? So I guess it would be like, if inside of to_path we passed a third argument that was basically the memory address to, it's almost like you're making a little custom stack of your own [LAUGH] that can kind of like, you can just kind of allocate some memory into. [00:09:01] But unlike malloc and free, with arenas, you never have to free them because you never have to free the individual allocations that you make into them. Because they basically say, okay, let me reserve a big chunk of memory here, and very time I want an allocation, I put it into that. diff --git a/en-US/2025-06-09-c-fundamentals/16-stack-vs-heap-memory.vtt b/en-US/2025-06-09-c-fundamentals/16-stack-vs-heap-memory.vtt index f7a138be..9b8e7271 100644 --- a/en-US/2025-06-09-c-fundamentals/16-stack-vs-heap-memory.vtt +++ b/en-US/2025-06-09-c-fundamentals/16-stack-vs-heap-memory.vtt @@ -11,7 +11,7 @@ we've got our struct stat metadata. 3 00:00:03.725 --> 00:00:07.075 -We're calling fstat and +We're calling fstat on the file descriptor, metadata address. 4 @@ -30,8 +30,8 @@ my metadata populated, 7 00:00:13.954 --> 00:00:18.846 -instead of saying char buffer bracket 100, -I can say char buffer metadata.st_size. +instead of saying char buffer[100], +I can say char buffer[metadata.st_size]. 8 00:00:18.846 --> 00:00:21.513 @@ -310,7 +310,7 @@ bytes I actually read. 65 00:03:17.609 --> 00:03:21.616 -Now, I think that can also happen is, +Now, a think that can also happen is, yeah, it can potentially say, look, 66 @@ -334,7 +334,7 @@ file in a single read call. 70 00:03:34.927 --> 00:03:38.090 -Nock was like, nah, nah, nah, +MacOS was like, nah, nah, nah, that's too many gigabytes, 71 @@ -506,7 +506,7 @@ dealing with stack memory. 105 00:05:28.077 --> 00:05:31.176 -We do need to grant to deal with +We do need to, granted, deal with the complexity of reading in chunks, but 106 @@ -534,7 +534,7 @@ very important. 111 00:05:43.103 --> 00:05:46.794 -Getting its size by using the Fstat, +Getting its size by using the fstat, and then we talked about structs and 112 @@ -559,7 +559,7 @@ theoretically, to do a malloc so 116 00:05:59.505 --> 00:06:02.855 -we can just skip the exact size, and +we can just get the exact size, and not worry about overflowing the stack. 117 @@ -584,7 +584,7 @@ about managing lifetimes, 121 00:06:14.774 --> 00:06:15.827 -remember when you call free. +remembering when to call free. 122 00:06:15.827 --> 00:06:19.317 @@ -835,7 +835,7 @@ how do I explain this concisely? 174 00:08:46.129 --> 00:08:50.024 So I guess it would be like, -if inside of two path we passed a third +if inside of to_path we passed a third 175 00:08:50.024 --> 00:08:53.199 diff --git a/en-US/2025-06-09-c-fundamentals/17-file-i-o-exercise.txt b/en-US/2025-06-09-c-fundamentals/17-file-i-o-exercise.txt index a5890e72..7ae750d4 100644 --- a/en-US/2025-06-09-c-fundamentals/17-file-i-o-exercise.txt +++ b/en-US/2025-06-09-c-fundamentals/17-file-i-o-exercise.txt @@ -1,14 +1,14 @@ [00:00:00] ->> Richard Feldman: Let's go through the part four exercise. So we're gonna start off by building and running the program, as we've been doing, cool. So you might notice that we're printing out what appears to be a gigantic index.html file, actually two of them. So it says index.html contents and then blah blog/index.html contents. +>> Richard Feldman: Let's go through the part four exercise. So we're gonna start off by building and running the program, as we've been doing, cool. So you might notice that we're printing out what appears to be a gigantic index.html file, actually two of them. So it says index.html contents and then blog/index.html contents. [00:00:22] -If you look inside the exercises folder, there are a couple of extra things in here. So there's this index.html. This is like, in addition to the all the dot c files, and it looks like this says, like, Hello World. This through slash page. In the future, when we get the actual web server running, we're gonna literally be like, serving this to a browser. +If you look inside the exercises folder, there are a couple of extra things in here. So there's this index.html. This is like, in addition to the all the .c files, and it looks like this says, like, Hello World. This is the root slash page. In the future, when we get the actual web server running, we're gonna literally be like, serving this to a browser. [00:00:39] But for right now it's just hard coded in our exercises directory. And then we also have a blog directory which has an index.html inside of it, which just says, this is a blog. And basically the only purpose of these two things is just to be able to verify that like our parsing and translating things into paths is actually working correctly. [00:00:56] -Cool, so, yeah. Let's build and ran the program. Let's take a look at what this is doing. So this part right here, this two path, this is gonna look familiar. This is basically just like, if you take what happened at the end of the solution for part three, this is what's there. +Cool, so, yeah. Let's build and ran the program. Let's take a look at what this is doing. So this part right here, this to_path, this is gonna look familiar. This is basically just like, if you take what happened at the end of the solution for part three, this is what's there. [00:01:12] So this has the like the refactor that we did. So all of this is just stuff that we've already seen before nothing new to see there. We just so still needed it because, we're building up to a static web server. Now we're going to have this new thing called print_file, which is basically like takes a path. @@ -17,16 +17,16 @@ So this has the like the refactor that we did. So all of this is just stuff that And this path is gonna be parsed out of the request from earlier. And then basically we're going to go through this whole process that we just learned about. So do the open to get the file descriptor, make the metadata struct, call fstat to populate it. Right now, by the way, you might notice that we are not handling any errors here, and we're gonna see why by the end of the exercise, we've chosen not to handle any errors. [00:01:49] -And here we say, change this charge star to and malloc, sorry. Change this to charge star and malloc. So right now, this is allocating metadata, st_size + 1, which as we saw from the slides, this is not safe. This could very easily blow the stack, and if we want to avoid that, malloc is one way to do that. +And here we say, change this char star and malloc, sorry. Change this to char star and malloc. So right now, this is allocating metadata.st_size + 1, which as we saw from the slides, this is not safe. This could very easily blow the stack, and if we want to avoid that, malloc is one way to do that. [00:02:05] And by the way, don't forget to handle the case for malloc returns null, which is what malloc returns when there's an error. So make sure that we handle errors, because malloc can fail to and also don't forget to call free on it at the appropriately making sure not to use use after free. [00:02:19] -Freeze, or double freeze, or anything like that. Just call free at the correct times so that this will free this actual memory after we malloc it, okay. And then finally, after we've done that, then just go back and add error handling for all the cases that could happen. +or double free, or anything like that. Just call free at the correct times so that this will free this actual memory after we malloc it, okay. And then finally, after we've done that, then just go back and add error handling for all the cases that could happen. [00:02:35] -So if you want to see some documentation for these different functions, this is like you. A little bit of a your first taste of, like, C documentation. But I do think that learning how to read C Docs is actually one of the most valuable things you can take away from this course. +So if you want to see some documentation for these different functions, this is like a little bit of a your first taste of, like, C documentation. But I do think that learning how to read C Docs is actually one of the most valuable things you can take away from this course. [00:02:48] Because if you're trying to do, interop with another language, or you're trying to, get a little tiny bit of C involved in a really performance critical section of something you're doing at work. This is, kind of the way to do that. And so these links will give you sort of a little sense of what that can look like. @@ -42,19 +42,19 @@ So this is the Linux version of this. In part six we're actually gonna see that, And we actually are gonna have to account for that difference, but for the rest of the workshop, you can just get away with looking for either the Linux docs or the BSD docs. And I think the Linux docs are a little easier to read, but basically, like this is a pretty representative example of like, what it looks like to read docs for Linux, like C functions. [00:04:03] -You can just kind of search for these on the web and just like open and then like maybe Linux or something like that, or even just like open and then see, and you'll get a lot of results from this website. This is man7.org. And basically, here's what it looks like. +You can just kind of search for these on the web and just like open and then like maybe Linux or something like that, or even just like open and then C, and you'll get a lot of results from this website. This is man7.org. And basically, here's what it looks like. [00:04:15] You've got a variety of related functions. They're sort of all defined in the same place. They're whoever wrote the docs decided to organize them this way, so here's open. Basically, all of these things are things that we have at some point seen. So const char, we haven't seen. [00:04:29] -I mean we saw const, but in a different context where it was sort of out at the top. And again, this just means, basically, you're not supposed to write into this. This is the pathname to open. So this is a char star, so terminated string int. We know about that one. +I mean we saw const, but in a different context where it was sort of out at the top. And again, this just means, basically, you're not supposed to write into this. This is the pathname to open. So this is a char star, so null terminated string, int, we know about that one. [00:04:42] -That's the flag. So this is, like the read only flag that we put there, the dot dot dot basically means Varg. So it means that you can optionally send additional arguments. And then this is just a little comment saying that, like, hey, there's like, one var arg that you're allowed to send, and it should be one of these mode t things. +That's the flag. So this is, like the read only flag that we put there, the "..." basically means vararg. So it means that you can optionally send additional arguments. And then this is just a little comment saying that, like, hey, there's like, one var arg that you're allowed to send, and it should be one of these mode t things. [00:04:57] -Mode_t is a struct that. That specifies, or actually, sorry, it might be flags, not sure, but the type for this is defined somewhere else. But this is basically like if you want the, yeah, some additional configuration around how you want to open the file. Then there's other functions like create and open app and open app two and stuff like that. +Mode_t is a struct that. That specifies, or actually, sorry, it might be flags, not sure, but the type for this is defined somewhere else. But this is basically like if you want the, yeah, some additional configuration around how you want to open the file. Then there's other functions like create and openat and openat2 and stuff like that. [00:05:17] We don't need to worry about these, but the point is just that like this is our first example of. Now we've learned enough that we can actually start reading C documentation, which opens up a whole world of exciting things to us. All right, having said all that, let's go ahead and go through these two things. @@ -75,22 +75,22 @@ So let's go ahead and handle that real quick. If buff double equals null, then w And then, of course, don't forget to free buff later to prevent memory leaks. So right down at the end here where we're closing the FD, let's free that. Great, okay, looking good. All right, there's that. Let's run the program again. And sure enough, everything looks great. We are now printing both of these files and we're doing it with malloc and free. [00:07:06] -I don't see what all the fuss is about. That was no proble, we just added a little free in there. All right, and now finally let's go back and add error handling 'cause we omitted that earlier, so let's go ahead and just do that. Here are the docs for all these things. +I don't see what all the fuss is about. That was no problem, we just added a little free in there. All right, and now finally let's go back and add error handling 'cause we omitted that earlier, so let's go ahead and just do that. Here are the docs for all these things. [00:07:17] So if you look at the docs for open, you can see that. It will say, hey, if FD is -1, then that means an error happened. And again, normally, we would like, handle this more gracefully. Print out, hey, no, I couldn't open this path, not found or something like that. [00:07:34] -Maybe look at what specific error had happened. But for our purposes, we're just like, yeah, just return no problem. So that's that one. Then we have stat which can also fail sorry, fstat. So gonna say, if this is w = -1 here, we're not bothering to introduce a variable because we're, we would only read it for error handling anyway. +Maybe look at what specific error had happened. But for our purposes, we're just like, yeah, just return no problem. So that's that one. Then we have stat which can also fail sorry, fstat. So gonna say, if this is == -1 here, we're not bothering to introduce a variable because we're, we would only read it for error handling anyway. [00:07:54] -So just go ahead and do that. Okay, all right. And read, okay, where is read there. It is great. And now I can just say if bytes_read w = -1 return and malloc, or is that one? We already did malloc, right? Yeah, great, okay, yeah, we can print of that an error handle, but I'm not going to bother. +So just go ahead and do that. Okay, all right. And read, okay, where is read? There it is, great. And now I can just say if bytes_read == -1 return and malloc, or is that one? We already did malloc, right? Yeah, great, okay, yeah, we can printf that an error happened, but I'm not going to bother. [00:08:19] All right, let me run the program again and we're all good because none of those error cases even came up and we're all done and everything is perfect and I didn't make any mistakes, right? Anyone see anything I didn't do correctly? Here's a question. Let's suppose that I'm coming along here and I'm like, I called malloc here and remember malloc. [00:08:38] -Does a long lived allocation on the heap that outlives the function, and then it's very important that we make sure to free that, otherwise we have a memory leak. So let's suppose we're coming down here, and we get down here and we're like, cool. We freed that. We didn't forget very good. +Does a long lived allocation on the heap that outlives the function, and then it's very important that we make sure to free that, otherwise we have a memory leak. So let's suppose we're coming down here, and we get down here and we're like, cool. We freed that. We didn't forget, very good. What if bytes_read was -1? Did we free it? Nope... [00:08:53] Did anyone notice that we didn't free it? Nope, we had a memory leak. [LAUGH] This is the problem, if you don't have any conditionals, yeah, sure, it's no problem. It's just free, no big deal. The problem is, real programs actually have lots of conditionals, and you have to remember to do that. @@ -98,7 +98,7 @@ Did anyone notice that we didn't free it? Nope, we had a memory leak. [LAUGH] Th [00:09:14] Here's another question. This one will be a little bit easier. Do we always close the file? >> Speaker 2: No. ->> Richard Feldman: Nope, [LAUGH] yeah, what if bites red was negative one? +>> Richard Feldman: Nope, [LAUGH] yeah, what if bytes_read was negative one? >> Speaker 2: We did an early return. >> Richard Feldman: We never reached this line. So yeah, we needed to close there too. @@ -106,19 +106,19 @@ Here's another question. This one will be a little bit easier. Do we always clos What about up here? Okay, if buff = null, we don't need to free it because it was null, so it didn't get allocated in the first place. But we did actually need to close the file descriptor there. What if this happened? Yeah, I also need you to close the file descriptor there. [00:09:41] -But here we need to not free because we haven't done the malloc yet. So, and then again here we don't need to close the file descriptor because this is for equals one which means that there was no file descriptor. This is the problem. This is why it's so easy to make these mistakes is because we're not usually accustomed to thinking in terms of yeah, it's just this chore, right? +But here we need to not free because we haven't done the malloc yet. So, and then again here we don't need to close the file descriptor because this is for equals -1 which means that there was no file descriptor. This is the problem. This is why it's so easy to make these mistakes is because we're not usually accustomed to thinking in terms of yeah, it's just this chore, right? [00:10:00] We're like, open it. And then just remember to close it at the end. You're done. You malloc it. And then just remember to free at the end and you're done. It's not actually that simple because in real world programs, you do have all sorts of conditionals going on. [00:10:11] -You have early returns. You have things that like only happen sometimes and other times don't happen. And you have to remember to close things in just the right spot, like close your file descriptors in just the right spot. And to free your malix in just the right spots. +You have early returns. You have things that like only happen sometimes and other times don't happen. And you have to remember to close things in just the right spot, like close your file descriptors in just the right spot. And to free your mallocs in just the right spots. [00:10:23] And again, as we talked earlier, if you don't remember to free at just the right time, you get a memory leak. If you free too early, you get a use after free, which is way worse than a memory leak. And if you free multiple times, and we are calling free, multiple times in this function, then you get a double free which is even worse than a use after free. [00:10:40] -This is how C gets a reputation for its memory on safety, causing problems deservedly. So, because this does really cause problems. Now one, right, you can go with this is you can go with rust, which basically, you don't have clothes entry in rust and rust. It just takes care of all these things automatically for you with plenty of other trade-offs, if you want to learn all about that, I have a whole course on Rust that you can watch right here on Final Masters. +This is how C gets a reputation for its memory unsafety, causing problems deservedly. So, because this does really cause problems. Now, one route you can go with this is you can go with Rust, which basically, you don't have close and free in Rust. It just takes care of all these things automatically for you with plenty of other trade-offs, if you want to learn all about that, I have a whole course on Rust that you can watch right here on Frontend Masters. [00:11:03] But it's also worth noting that, again, if we choose not to use malloc in the first place. If we're going to do our chunked reads anyway, and we're gonna just do them on the stack, then I don't need to worry about any of this. I don't need to do the free thing because I have chosen to organize my program in a way where I didn't have to use malloc and therefore I don't have to use free and the entire category of bugs just goes away. @@ -130,16 +130,16 @@ Granted, other trade offs happen, but I get better performance, and I don't have Then you have a file descriptor leak on the plus side, file descriptor leaks are generally not they tend not to be as consequential as memory leaks, although, granted. It can be kind of annoying if you have a very long running program, but eventually you run out of file descriptors. [00:11:58] -That is annoying. One other note about this is that this right here, is actually one of the major things that the sort of C successor languages that are not in the like c++ or rust family. So this is like Zig, Jai and Odin. I believe all three of them do this is that they have a keyword called Defer. +That is annoying. One other note about this is that this right here, is actually one of the major things that the sort of C successor languages that are not in the like C++ or Rust family. So this is like Zig, Jai and Odin. I believe all three of them do this is that they have a keyword called Defer. [00:12:16] -And basically what defer lets you do is that I'm just gonna make up syntactic because c does not have this is you basically say something like this, defer. I guess that would probably be down here, actually. So C, if it's negative one, if so early return. And then basically what defer means is basically like at the end of the function, whenever the function returns, whether that's just because the function naturally ended. +And basically what defer lets you do is that I'm just gonna make up syntactic because C does not have this is you basically say something like this, defer. I guess that would probably be down here, actually. So see if it's negative one, if so early return. And then basically what defer means is basically like at the end of the function, whenever the function returns, whether that's just because the function naturally ended. [00:12:37] Or because we did an early return, just make sure you always do this close fd. And then now you wouldn't need this, and you wouldn't need this, and you wouldn't need this, and you could do the same thing for free if you wanted to. Now, granted, that only works if, like you're doing this inside the scope of this one function, like, if that works fine for closing a file descriptor. [00:12:52] -But if the whole point of the malloc that you're doing is that you want to return. The thing that it malloced from the function then defer doesn't really help you, whereas, like the things that rust does do help you. But it is worth noting that, especially for things like file descriptors, this is a major ergonomics improvement that these languages give you. +But if the whole point of the malloc that you're doing is that you want to return. The thing that it malloced from the function then defer doesn't really help you, whereas, like the things that Rust does do help you. But it is worth noting that, especially for things like file descriptors, this is a major ergonomics improvement that these languages give you. [00:13:10] And I have heard talk about people trying to add this to C, or, like, writing proposals to do that, but C being a 50 plus your old language. New features don't just get added on a whim. [LAUGH] it's like a long process to get things through the standards. diff --git a/en-US/2025-06-09-c-fundamentals/17-file-i-o-exercise.vtt b/en-US/2025-06-09-c-fundamentals/17-file-i-o-exercise.vtt index d3970517..5e766e77 100644 --- a/en-US/2025-06-09-c-fundamentals/17-file-i-o-exercise.vtt +++ b/en-US/2025-06-09-c-fundamentals/17-file-i-o-exercise.vtt @@ -26,7 +26,7 @@ index.html file, actually two of them. 6 00:00:17.706 --> 00:00:22.375 So it says index.html contents and -then blah blog/index.html contents. +then blog/index.html contents. 7 00:00:22.375 --> 00:00:24.580 @@ -44,7 +44,7 @@ So there's this index.html. 10 00:00:28.117 --> 00:00:31.357 This is like, in addition to the all the -dot c files, and it looks like this says, +.c files, and it looks like this says, 11 00:00:31.357 --> 00:00:32.225 @@ -52,7 +52,7 @@ like, Hello World. 12 00:00:32.225 --> 00:00:34.572 -This through slash page. +This is the root slash page. 13 00:00:34.572 --> 00:00:36.930 @@ -106,7 +106,7 @@ Let's take a look at what this is doing. 24 00:01:04.518 --> 00:01:07.719 -So this part right here, this two path, +So this part right here, this to_path, this is gonna look familiar. 25 @@ -186,16 +186,16 @@ we've chosen not to handle any errors. 41 00:01:49.417 --> 00:01:52.684 And here we say, change this -charge star to and malloc, sorry. +char star and malloc, sorry. 42 00:01:52.684 --> 00:01:54.266 -Change this to charge star and malloc. +Change this to char star and malloc. 43 00:01:54.266 --> 00:01:57.493 So right now, -this is allocating metadata, st_size + 1, +this is allocating metadata.st_size + 1, 44 00:01:57.493 --> 00:02:00.107 @@ -237,7 +237,7 @@ sure not to use use after free. 52 00:02:19.790 --> 00:02:21.318 -Freeze, or double freeze, +or double free, or anything like that. 53 @@ -266,11 +266,11 @@ for these different functions, 58 00:02:38.792 --> 00:02:39.680 -this is like you. +this is like 59 00:02:39.680 --> 00:02:42.712 -A little bit of a your first taste of, +a little bit of a your first taste of, like, C documentation. 60 @@ -392,7 +392,7 @@ these on the web and just like open and 84 00:04:05.805 --> 00:04:09.218 then like maybe Linux or something like -that, or even just like open and then see, +that, or even just like open and then C, 85 00:04:09.218 --> 00:04:11.361 @@ -451,11 +451,11 @@ This is the pathname to open. 97 00:04:38.321 --> 00:04:41.198 So this is a char star, -so terminated string int. +so null terminated string, int, 98 00:04:41.198 --> 00:04:42.187 -We know about that one. +we know about that one. 99 00:04:42.187 --> 00:04:42.798 @@ -468,7 +468,7 @@ like the read only flag that we put there, 101 00:04:45.859 --> 00:04:48.053 -the dot dot dot basically means Varg. +the "..." basically means vararg. 102 00:04:48.053 --> 00:04:51.037 @@ -511,7 +511,7 @@ how you want to open the file. 110 00:05:13.210 --> 00:05:16.320 Then there's other functions like create -and open app and open app two and +and openat and openat2 and 111 00:05:16.320 --> 00:05:17.084 @@ -693,7 +693,7 @@ I don't see what all the fuss is about. 150 00:07:08.338 --> 00:07:10.403 -That was no proble, +That was no problem, we just added a little free in there. 151 @@ -751,7 +751,7 @@ also fail sorry, fstat. 162 00:07:47.156 --> 00:07:50.631 -So gonna say, if this is w = -1 here, +So gonna say, if this is == -1 here, we're not bothering to introduce 163 @@ -769,19 +769,19 @@ Okay, all right. 166 00:07:58.970 --> 00:08:02.610 -And read, okay, where is read there. +And read, okay, where is read? There 167 00:08:02.610 --> 00:08:03.608 -It is great. +it is, great. 168 00:08:03.608 --> 00:08:08.525 -And now I can just say if bytes_read w = +And now I can just say if bytes_read == -1 169 00:08:08.525 --> 00:08:13.592 --1 return and malloc, or is that one? +return and malloc, or is that one? 170 00:08:13.592 --> 00:08:15.524 @@ -790,7 +790,7 @@ We already did malloc, right? 171 00:08:15.524 --> 00:08:18.193 Yeah, great, okay, yeah, -we can print of that an error handle, but +we can printf that an error happened, but 172 00:08:18.193 --> 00:08:19.207 @@ -849,7 +849,8 @@ We freed that. 184 00:08:51.605 --> 00:08:53.775 -We didn't forget very good. +We didn't forget, very good. +What if bytes_read was -1? Did we free it? Nope... 185 00:08:53.775 --> 00:08:57.880 @@ -900,7 +901,7 @@ Do we always close the file? 196 00:09:23.170 --> 00:09:26.258 >> Richard Feldman: Nope, [LAUGH] yeah, -what if bites red was negative one? +what if bytes_read was negative one? 197 00:09:26.258 --> 00:09:27.105 @@ -955,7 +956,7 @@ close the file descriptor because this is 208 00:09:47.691 --> 00:09:50.559 -for equals one which means that +for equals -1 which means that there was no file descriptor. 209 @@ -1025,7 +1026,7 @@ in just the right spot. 223 00:10:21.110 --> 00:10:23.305 -And to free your malix +And to free your mallocs in just the right spots. 224 @@ -1059,7 +1060,7 @@ which is even worse than a use after free. 230 00:10:40.256 --> 00:10:43.183 This is how C gets a reputation for -its memory on safety, +its memory unsafety, 231 00:10:43.183 --> 00:10:44.876 @@ -1072,13 +1073,12 @@ really cause problems. 233 00:10:48.047 --> 00:10:51.637 -Now one, right, you can go with this is -you can go with rust, which basically, +Now, one route you can go with this is +you can go with Rust, which basically, 234 00:10:51.637 --> 00:10:53.790 -you don't have clothes entry in rust and -rust. +you don't have close and free in Rust. 235 00:10:53.790 --> 00:10:56.444 @@ -1093,7 +1093,7 @@ if you want to learn all about that, 237 00:11:00.001 --> 00:11:03.576 I have a whole course on Rust that you -can watch right here on Final Masters. +can watch right here on Frontend Masters. 238 00:11:03.576 --> 00:11:06.843 @@ -1198,8 +1198,8 @@ that the sort of C successor languages 259 00:12:06.753 --> 00:12:09.323 -that are not in the like c++ or -rust family. +that are not in the like C++ or +Rust family. 260 00:12:09.323 --> 00:12:12.636 @@ -1217,7 +1217,7 @@ that I'm just gonna make up syntactic 263 00:12:21.218 --> 00:12:25.690 -because c does not have this is you +because C does not have this is you basically say something like this, defer. 264 @@ -1227,7 +1227,7 @@ actually. 265 00:12:27.449 --> 00:12:29.466 -So C, if it's negative one, +So see if it's negative one, if so early return. 266 @@ -1282,7 +1282,7 @@ function then defer doesn't really help 276 00:13:00.027 --> 00:13:02.897 you, whereas, like the things -that rust does do help you. +that Rust does do help you. 277 00:13:02.897 --> 00:13:06.777 diff --git a/en-US/2025-06-09-c-fundamentals/18-open-socket-listen-for-connections.txt b/en-US/2025-06-09-c-fundamentals/18-open-socket-listen-for-connections.txt index e409f45b..f7e59ac8 100644 --- a/en-US/2025-06-09-c-fundamentals/18-open-socket-listen-for-connections.txt +++ b/en-US/2025-06-09-c-fundamentals/18-open-socket-listen-for-connections.txt @@ -35,7 +35,7 @@ And we're gonna talk about these constants. This is the interesting part here, t And so what this is doing is it's saying, I wanna pass in the address of this integer, and then setsockopt is actually going to mutate that integer. So this is the same kind of pattern as what we saw earlier with memcopy. Where we were like, hey, I'm gonna give you the address of these bytes, I want you to stomp all over them. [00:03:18] -Or what we saw later on with fsat, where we're like, hey, here's this struct. I'm gonna give you the address, I want you to stomp all over it. Now we're doing that same thing, but we're doing it with an individual integer. So there's really no limit to how much C [LAUGH] libraries will use this pattern. +Or what we saw later on with fstat, where we're like, hey, here's this struct. I'm gonna give you the address, I want you to stomp all over it. Now we're doing that same thing, but we're doing it with an individual integer. So there's really no limit to how much C [LAUGH] libraries will use this pattern. [00:03:30] Once again, this is C standard library, ships with the operating system. And it's like, yeah, give me the address of this integer, I'm going to stomp all over it when you call me, that's how these things work. Or, sorry, it potentially will stomp all over it, it doesn't necessarily have to. @@ -68,7 +68,7 @@ Okay, yeah, so this is just kind of a weird API for how they decided to do that. I chose localhost:8080, you can choose whatever you want. Some of them use like 3000 or 1337 or 8000 or something like that, just went with 8080, it's one of the common ones. Basically, we're making this struct. Once again, we are initially declaring this struct as just empty plain old bytes here. [00:06:19] -So this is all initialized memory, and then we're just gonna go through and initialize that. We're gonna say address.sin_family = AF_INET, this is IPv4 again. [COUGH] Then, within this thing, we're setting the s_addr. Worth noting that this thing right here is another struct that's uninitialized, we're only setting one field in that struct. +So this is all uninitialized memory, and then we're just gonna go through and initialize that. We're gonna say address.sin_family = AF_INET, this is IPv4 again. [COUGH] Then, within this thing, we're setting the s_addr. Worth noting that this thing right here is another struct that's uninitialized, we're only setting one field in that struct. [00:06:38] Again, [LAUGH] this is C, sometimes the APIs are kind of strange. And this is basically saying, I don't care, I just want any address, which means the other fields are just gonna be ignored. So we don't even bother to initialize them. And then finally we have the port. @@ -101,7 +101,7 @@ And so bind wants you to essentially say, hey, tell me about the actual subset o So again, a little bit of a strange API there, but nothing that we haven't seen before. It's just might feel a little bit strange and kind of unergonomic. Yeah, so this is just the the casting to say, okay, we're treating this memory address as a sockaddr address, rather than a sockaddr_in address. [00:09:31] -As opposed to sockaddr, I think it's in6 is the IPv6 version of that, in6, that's what it is, right? So basically, what this is doing is saying, okay, we have the first two fields of sockaddr_in, which is sa_family_t, and uint16_t for the port. Same kind of basic thing right here, in6 has these same two first fields. +As opposed to sockaddr, I think it's in6 is the IPv6 version of that. In6, that's what it is, right. So basically, what this is doing is saying, okay, we have the first two fields of sockaddr_in, which is sa_family_t, and uint16_t for the port. Same kind of basic thing right here, in6 has these same two first fields. [00:09:51] And sockaddr, the sort of generic struct that is like, I'm sort of compatible with either of these. The first field is the same, so this is the subset that we care about. The sa_family refers to either the sin6 family or the sin family, depending on it's IPv6 or IPv4. diff --git a/en-US/2025-06-09-c-fundamentals/18-open-socket-listen-for-connections.vtt b/en-US/2025-06-09-c-fundamentals/18-open-socket-listen-for-connections.vtt index 3025d0bc..d1b3d71c 100644 --- a/en-US/2025-06-09-c-fundamentals/18-open-socket-listen-for-connections.vtt +++ b/en-US/2025-06-09-c-fundamentals/18-open-socket-listen-for-connections.vtt @@ -318,7 +318,7 @@ bytes, I want you to stomp all over them. 67 00:03:18.814 --> 00:03:21.985 -Or what we saw later on with fsat, +Or what we saw later on with fstat, where we're like, hey, here's this struct. 68 @@ -593,7 +593,7 @@ as just empty plain old bytes here. 125 00:06:19.581 --> 00:06:22.077 -So this is all initialized memory, and +So this is all uninitialized memory, and then we're just gonna go through and 126 @@ -878,11 +878,11 @@ rather than a sockaddr_in address. 184 00:09:31.588 --> 00:09:35.986 As opposed to sockaddr, I think it's -in6 is the IPv6 version of that, in6, +in6 is the IPv6 version of that. In6, 185 00:09:35.986 --> 00:09:37.573 -that's what it is, right? +that's what it is, right. 186 00:09:37.573 --> 00:09:42.704 @@ -921,7 +921,7 @@ either the sin6 family or 193 00:10:04.549 --> 00:10:08.598 -the sin family, +the sa family, depending on it's IPv6 or IPv4. 194 diff --git a/en-US/2025-06-09-c-fundamentals/19-read-write-to-a-socket.txt b/en-US/2025-06-09-c-fundamentals/19-read-write-to-a-socket.txt index d257c91f..ec741ddc 100644 --- a/en-US/2025-06-09-c-fundamentals/19-read-write-to-a-socket.txt +++ b/en-US/2025-06-09-c-fundamentals/19-read-write-to-a-socket.txt @@ -1,8 +1,8 @@ [00:00:00] ->> Richard Feldman: Next thing we need to do is we need to actually, read a request out of the socket. So the first way we're gonna do this is, I'm gonna start by just saying, I'm gonna make a char of a request array. This is going to end up being the string that we're going to send to our to path function. +>> Richard Feldman: Next thing we need to do is we need to actually, read a request out of the socket. So the first way we're gonna do this is, I'm gonna start by just saying, I'm gonna make a char of a request array. This is going to end up being the string that we're going to send to our to_path function. [00:00:16] -So what we wanna do is, we wanna just get the bytes from the network into this slot, and I'm gonna pass this address off to our to path function that we wrote back in part three, yeah. And basically, I'm hard-coding, max request bytes plus 1, allocating this many bytes on the stack. +So what we wanna do is, we wanna just get the bytes from the network into this slot, and I'm gonna pass this address off to our to_path function that we wrote back in part three, yeah. And basically, I'm hard-coding, max request bytes plus 1, allocating this many bytes on the stack. [00:00:36] So there are two reasons I'm doing this. One, as we saw in the previous section, if I can avoid using malloc, I would like to avoid using malloc. And two is because, I mean, I guess this is kind of a naturally, like we're gonna chunk it up type of a thing when you are getting request bytes in from the network. @@ -17,13 +17,13 @@ You're just asking to get DOS [LAUGH] somebody is gonna send you some gigantic t Okay, then we're gonna make something called addrlen, which is the size of this address. I'm just using that because we're gonna reuse this later, and I wanna have to keep calling size of address over and over. And then, the next thing we're gonna do is while 1, does anyone know what while 1 does? [00:01:46] -Infinite loop, yes, exactly, same thing as while 2, except again, this is C. So often, you'll see literally, I bet if you search GitHub for wild parentheses, one, you'll find quite a lot of those in C repos. And basically what's happening here is we're just essentially saying, look, inside this loop, what I'm about to do, and we're gonna see the actual code for this in a sec. +Infinite loop, yes, exactly, same thing as while true, except again, this is C. So often, you'll see literally, I bet if you search GitHub for while (1), you'll find quite a lot of those in C repos. And basically what's happening here is we're just essentially saying, look, inside this loop, what I'm about to do, and we're gonna see the actual code for this in a sec. [00:02:05] -I'm just going to run a function that just says, wait, do not advance, do not run the next line of code until a request has come in on this socket on port 8080. And once it does then we're gonna start handling stuff, and the reason is so, one is because, all we wanna be listening on this indefinitely. +I'm just going to run a function that just says, wait, do not advance, do not run the next line of code until a request has come in on this socket on port 8080. And once it does then we're gonna start handling stuff, and the reason its while (1) is because, all we wanna be listening on this indefinitely. [00:02:21] -This is how static HTTP servers work, they just keep working until you Ctrl C 11 and shut them down manually. That's exactly what we wanna do, we wanna just keep listening for the request to come in, as they keep coming in we wanna keep handling them, and that's all our program is gonna do. +This is how static HTTP servers work, they just keep working until you Ctrl+C them and shut them down manually. That's exactly what we wanna do, we wanna just keep listening for the request to come in, as they keep coming in we wanna keep handling them, and that's all our program is gonna do. [00:02:34] So this program, by design, is never going to exit unless maybe there's some sort of unexpected error that we don't think we can recover from, cool. Okay, so here is the body of the while loop. So we're basically gonna start off by saying, okay, I need to get a request socket file descriptor. @@ -32,13 +32,13 @@ So this program, by design, is never going to exit unless maybe there's some sor We'll talk about why we're doing that in a sec, and I call a function called accept, which takes the socket file descriptor. So remember that the socket was something we set up outside the while loop. This is a second file descriptor that setting inside the while loop. We're doing this once again, this weird like, socket address thing, the casting. [00:03:08] -This is exactly the same trick that we were doing back here for bind, if you remember this thing where we're doing the parsing the address of this and then casting it to the socket, or then passing the size of the address. Same exact thing that we were doing there except this time, we're doing it for accept instead of bind. +This is exactly the same trick that we were doing back here for bind, if you remember this thing where we're doing the passing the address of this and then casting it to the sockaddr then passing the size of the address. Same exact thing that we were doing there except this time, we're doing it for accept instead of bind. [00:03:24] So the difference between accept and bind is that if we were doing a multithreaded application, which we're not. But if we were, then we would want to be able to say, okay, I want to, in parallel, be able to process multiple requests at the same time on different cores of my CPU. [00:03:40] -So you might imagine that we would say, okay, I'm gonna call accept, and we're not gonna do any multithreading in this course, this is a C fundamentals, not C multi-threading, which is a whole thing. But conceptually, if you imagine we're like okay, I'm listening on this port. I have accepted something that is, say, I waited until some new thing came in, I got it. +So you might imagine that we would say, okay, I'm gonna call accept, and we're not gonna do any multithreading in this course, this is a C fundamentals, not C multi-threading, which is a whole thing. But conceptually, if you imagine we're like okay, I'm listening on this port. I have accepted something, that is to say, I waited until some new thing came in, I got it. [00:03:58] I'm like, great, I've got this handle to the file descriptor for this particular request, the bytes that are coming off of this. Now, I wanna read those bytes. I wanna do various operations on those bytes, other than read, which we'll see in a later part. Maybe I wanna just say, look, just hey, just throw that on a different CPU core, I wanna have that, go and do those things. @@ -62,22 +62,22 @@ Technically speaking, if you wanted to be absolutely really pedantic about it, y So if we wrote a close after the infinite loop, it would never get reached anyway, so who cares, but if we did an early return, I guess you technically should do that. But at the end of the day, once the program itself exits, the operating system is gonna close all these for you anyway. [00:05:53] -So you don't really need to bother to accept as a matter of just kinda bookkeeping peace of mind, feeling a little itch when you open something without closing it, that type of thing. It's not gonna matter one way or the other. Okay, [COUGH] so basically wait for that, and we talked about that request queue that can stack up as we're processing these. +So you don't really need to bother to except as a matter of just kinda bookkeeping peace of mind, feeling a little itch when you open something without closing it, that type of thing. It's not gonna matter one way or the other. Okay, [COUGH] so basically wait for that, and we talked about that request queue that can stack up as we're processing these. [00:06:10] -Basically, as soon as the queue gets a new connection, dequeue it as a new socket, and then we can do stuff with that socket, which is what we're gonna do in the middle here. So again, this is sort of dot.dot, that was all the stuff we saw on the previous slide. +Basically, as soon as the queue gets a new connection, dequeue it as a new socket, and then we can do stuff with that socket, which is what we're gonna do in the middle here. So again, this is sort of ( ... ), that was all the stuff we saw on the previous slide. [00:06:23] Now we're gonna call that same read function that we used for file I/O, it's exactly the same function. And now we're just giving it the socket file descriptor instead of the file on the file system. And again, Unix loves this file descriptor, C loves file descriptors, it just reuses the same function. [00:06:40] -So when we call read on this socket file descriptor, it's exactly as we call it on a file descriptor from the file system. It works exactly the same way. We say give it the destination, I'm gonna stop all over that, this is req, that's a way that we'd allocated with max request bytes. +So when we call read on this socket file descriptor, it's exactly as we call it on a file descriptor from the file system. It works exactly the same way. We say give it the destination, I'm gonna stomp all over that, this is req, that's our array that we'd allocated with max request bytes, back up here. [00:06:57] We tell it how many we wanna read up to this many, exactly the same way we did in part four, and then we get back the number of bytes read. We check to see if that was -1, etc. So now, we have populated our request with the contents of what came in over the network on port 8080, cool. [00:07:16] -Now, we're basically sort of home free, we can just proceed doing the same kind of stuff that we did before. So we say, call to path like we did everything we've been building up to at this point, we give it the req. It stomps all over those bytes, but that's fine because we're done with them [LAUGH], we don't need to ever look at the requests ever again. +Now, we're basically sort of home free, we can just proceed doing the same kind of stuff that we did before. So we say, call to_path like we did everything we've been building up to at this point, we give it the req. It stomps all over those bytes, but that's fine because we're done with them [LAUGH], we don't need to ever look at the requests ever again. [00:07:32] We've got our path here, we're gonna do the whole fd equals open, read only. And remember to close it again because we don't wanna file descript or leak on that one either, get the metadata, all of that stuff, read the contents, yada, yada. And now, basically, we just say write 1 contents length, to write those contents to standard out. @@ -86,10 +86,10 @@ We've got our path here, we're gonna do the whole fd equals open, read only. And Now, at this point, we haven't quite made a static HTTP server because what we do is we listen on port 8080. Whenever we get a request on port 8080, we process it, we turn it into a file and then we basically just say, okay, I've open this file and I've read this content. [00:08:06] -So index.html or blog index.html, whatever, and then I just write it to standard out, I just spit it out onto the screen, and that's it. That totally works, but of course, that's not quite a static HTTP server, but we have come a long way [LAUGH] we are now doing like, almost the entire thing. +So index.html or blog/index.html, whatever, and then I just write it to standard out, I just spit it out onto the screen, and that's it. That totally works, but of course, that's not quite a static HTTP server, but we have come a long way [LAUGH] we are now doing like, almost the entire thing. [00:08:21] -If I run this code in, and then I open up a browser and type in localhost port 8080, it's actually gonna do all this stuff like for real, and we're gonna process the requests. We're gonna open the contents of like index. If I type in localhost 8080/blog, it's gonna print out the contents of blog/index on HTML, all of that's gonna work right here using all this stuff that we've done up to this point. +If I run this code in, and then I open up a browser and type in localhost port 8080, it's actually gonna do all this stuff like for real, and we're gonna process the requests. We're gonna open the contents of like index. If I type in localhost:8080/blog, it's gonna print out the contents of blog/index.html, all of that's gonna work right here using all this stuff that we've done up to this point. [00:08:43] And all I have to do if I wanna make it a real HTTP server, instead of writing to standard out, just write it to the socket, that's it, right there, bam. Just same function as we did in hello world, hello metal. The same exact thing, write 1, we just changed the 1 that was hard-coded to write to standard out, and instead, just say, write it back to the socket. @@ -98,7 +98,7 @@ And all I have to do if I wanna make it a real HTTP server, instead of writing t And now, instead of printing it out to stand it out, it's gonna print it out back to the socket, which means that the browser is gonna see the response. So essentially, at that point, all we need to do is make sure that like contents is actually formatted as an HTTP response [LAUGH] instead of the raw contents of the file, and we're all set. [00:09:19] -So in order to do that, we can actually just like, keep the content says its own right, and we can just manually write 200 okay and then a blank line, which as it turns out is the requests, sorry, the response format that we need. And that's it, that's all we really need to do. +So in order to do that, we can actually just like, keep the contents as its own write, and we can just manually write 200 okay and then a blank line, which as it turns out is the requests, sorry, the response format that we need. And that's it, that's all we really need to do. [00:09:35] We can basically just say all these things up here, write this header, and then write the contents, and we're done, that's it, cool. So to recap, all the stuff we did in this while loop, first, accept waits for a new connection and then gives us a file descriptor. @@ -107,10 +107,10 @@ We can basically just say all these things up here, write this header, and then So importantly, accept will not run the next line of code, it just sits there and waits. It's just blocks and then does not let the program advance until a new connection comes in off the queue, if there's a queue of them backed up. And then gives us a file descriptor, which is a socket that's specific to that 1 connection coming from the browser. [00:10:10] -Then we can call read on it, these are getting the actual bytes that the browser was sending us. If we want, we can call read multiple times, we can chunk it up, no problem. It works the same way as read does on the file system. Then we call to path, which was the function that we wrote back in part three, to parse those request bytes into a file system path like index.html or blog/index.html, whatever, based on the request that we got from the browser. +Then we can call read on it, these are getting the actual bytes that the browser was sending us. If we want, we can call read multiple times, we can chunk it up, no problem. It works the same way as read does on the file system. Then we call to_path, which was the function that we wrote back in part three, to parse those request bytes into a file system path like index.html or blog/index.html, whatever, based on the request that we got from the browser. [00:10:32] -And then we do the open fstat read thing that we did in the previous section to get the file's full contents. And then finally, we write the full contents of the file back to the socket after that little HTTP 200 okay, header in there. And then we actually get to see this thing work [LAUGH], cool. +And then we do the open, fstat, read thing that we did in the previous section to get the file's full contents. And then finally, we write the full contents of the file back to the socket after that little HTTP 200 okay, header in there. And then we actually get to see this thing work [LAUGH], cool. [00:10:49] So, to summarize everything we talked about. First, open the socket. So opening the socket is as simple as just doing some little boilerplate stuff, in some cases with some kinda funky APIs. But hopefully everybody was able to roll with those being a little bit strange, but at least understandable. @@ -119,8 +119,8 @@ So, to summarize everything we talked about. First, open the socket. So opening Well, maybe not being 100% clear on exactly why they decided to do that, the way that they did. Then listening for the connections, so that's basically where we say, bind it to a particular port, and then now that port is going to send things to those sockets. We talked about reading from a socket, where inside the while loop we're doing accept to turn those individual connections into their own sockets. [00:11:24] -And then we can just read from those just using the exact same read function that we did in the file I/O section. And then finally, once we've read those in there, we take the request that we read in, we call to path on it, read from the file system to get the contents of that file, and finally, write the contents of that file back out to the socket, bam. +And then we can just read from those just using the exact same read function that we did in the file I/O section. And then finally, once we've read those in there, we take the request that we read in, we call to_path on it, read from the file system to get the contents of that file, and finally, write the contents of that file back out to the socket, bam. [00:11:39] -Using exactly the same write that we did all the way, part one, hello world on the metal. Same exact right function accept instead of one, we just write it to the socket. +Using exactly the same write that we did all the way, part one, hello world on the metal. Same exact write function except instead of 1, we just write it to the socket. diff --git a/en-US/2025-06-09-c-fundamentals/19-read-write-to-a-socket.vtt b/en-US/2025-06-09-c-fundamentals/19-read-write-to-a-socket.vtt index 034fb603..e09ce31b 100644 --- a/en-US/2025-06-09-c-fundamentals/19-read-write-to-a-socket.vtt +++ b/en-US/2025-06-09-c-fundamentals/19-read-write-to-a-socket.vtt @@ -21,7 +21,7 @@ I'm gonna make a char of a request array. 5 00:00:11.262 --> 00:00:15.436 This is going to end up being the string -that we're going to send to our to path +that we're going to send to our to_path 6 00:00:15.436 --> 00:00:16.099 @@ -39,7 +39,7 @@ I'm gonna pass this address off 9 00:00:25.420 --> 00:00:30.430 -to our to path function that we +to our to_path function that we wrote back in part three, yeah. 10 @@ -163,7 +163,7 @@ does anyone know what while 1 does? 35 00:01:46.828 --> 00:01:50.426 Infinite loop, yes, exactly, same thing -as while 2, except again, this is C. +as while true, except again, this is C. 36 00:01:50.426 --> 00:01:54.286 @@ -172,7 +172,7 @@ I bet if you search GitHub for 37 00:01:54.286 --> 00:01:58.520 -wild parentheses, one, you'll find +while (1), you'll find quite a lot of those in C repos. 38 @@ -202,17 +202,17 @@ has come in on this socket on port 8080. 43 00:02:14.685 --> 00:02:18.447 And once it does then we're gonna start -handling stuff, and the reason is so, +handling stuff, and the reason its 44 00:02:18.447 --> 00:02:21.582 -one is because, all we wanna be +while (1) is because, all we wanna be listening on this indefinitely. 45 00:02:21.582 --> 00:02:26.003 This is how static HTTP servers work, they -just keep working until you Ctrl C 11 and +just keep working until you Ctrl+C them and 46 00:02:26.003 --> 00:02:27.387 @@ -289,11 +289,11 @@ we were doing back here for bind, 61 00:03:11.473 --> 00:03:15.411 if you remember this thing where we're -doing the parsing the address of this and +doing the passing the address of this and 62 00:03:15.411 --> 00:03:18.977 -then casting it to the socket, or +then casting it to the sockaddr then passing the size of the address. 63 @@ -350,7 +350,7 @@ like okay, I'm listening on this port. 74 00:03:53.372 --> 00:03:58.269 -I have accepted something that is, say, +I have accepted something, that is to say, I waited until some new thing came in, 75 @@ -533,7 +533,7 @@ close all these for you anyway. 112 00:05:53.154 --> 00:05:56.217 So you don't really need to bother -to accept as a matter of just kinda +to except as a matter of just kinda 113 00:05:56.217 --> 00:05:59.549 @@ -576,7 +576,7 @@ do in the middle here. 121 00:06:19.028 --> 00:06:21.081 -So again, this is sort of dot.dot, +So again, this is sort of ( ... ), 122 00:06:21.081 --> 00:06:23.946 @@ -628,12 +628,12 @@ It works exactly the same way. 132 00:06:47.676 --> 00:06:52.220 We say give it the destination, -I'm gonna stop all over that, +I'm gonna stomp all over that, 133 00:06:52.220 --> 00:06:57.474 -this is req, that's a way that we'd -allocated with max request bytes. +this is req, that's our array that we'd +allocated with max request bytes, back up here. 134 00:06:57.474 --> 00:07:01.421 @@ -670,7 +670,7 @@ kind of stuff that we did before. 141 00:07:21.272 --> 00:07:25.085 -So we say, call to path like we did +So we say, call to_path like we did everything we've been building up to at 142 @@ -732,7 +732,7 @@ open this file and I've read this content. 154 00:08:06.346 --> 00:08:10.446 -So index.html or blog index.html, +So index.html or blog/index.html, whatever, and then I just write it to 155 @@ -771,12 +771,12 @@ the contents of like index. 162 00:08:34.055 --> 00:08:36.164 -If I type in localhost 8080/blog, +If I type in localhost:8080/blog, 163 00:08:36.164 --> 00:08:40.008 it's gonna print out the contents of -blog/index on HTML, all of that's +blog/index.html, all of that's 164 00:08:40.008 --> 00:08:43.987 @@ -835,11 +835,11 @@ contents of the file, and we're all set. 175 00:09:19.356 --> 00:09:23.860 So in order to do that, we can actually -just like, keep the content says its own +just like, keep the contents its own 176 00:09:23.860 --> 00:09:28.026 -right, and we can just manually write +write, and we can just manually write 200 okay and then a blank line, 177 @@ -921,7 +921,7 @@ does on the file system. 193 00:10:20.474 --> 00:10:24.534 -Then we call to path, which was the +Then we call to_path, which was the function that we wrote back in part three, 194 @@ -936,7 +936,7 @@ the request that we got from the browser. 196 00:10:32.741 --> 00:10:36.151 -And then we do the open fstat read thing +And then we do the open, fstat, read, thing that we did in the previous section to get 197 @@ -1030,7 +1030,7 @@ there, we take the request that we read 216 00:11:32.313 --> 00:11:35.548 -in, we call to path on it, read from +in, we call to_path on it, read from the file system to get the contents of 217 @@ -1049,6 +1049,6 @@ hello world on the metal. 220 00:11:44.244 --> 00:11:49.513 -Same exact right function accept instead -of one, we just write it to the socket. +Same exact write function except instead +of 1, we just write it to the socket. diff --git a/en-US/2025-06-09-c-fundamentals/2-hello-world-in-c.txt b/en-US/2025-06-09-c-fundamentals/2-hello-world-in-c.txt index d836ea71..157d54de 100644 --- a/en-US/2025-06-09-c-fundamentals/2-hello-world-in-c.txt +++ b/en-US/2025-06-09-c-fundamentals/2-hello-world-in-c.txt @@ -14,13 +14,13 @@ We're gonna talk about the performance implications of being this close to the h That's a little bit more ergonomic and maybe more idiomatic. Okay, so we got our nice metal font here. Any Iron Maiden fans in the house? So this is basically the close to the metal Hello, World in C. So let's kind of go through the different parts of what we got here. [00:01:14] -So essentially, this pound include here, we're gonna talk about what the pound sign means later on, this is a preprocessor directive. But basically this just means import the contents of this library here. So this is unistd.h, I don't know, universal standard, or something like that. And this is what gives us this right function that we're using right there. +So essentially, this "#include" here, we're gonna talk about what the pound sign means later on, this is a preprocessor directive. But basically this just means import the contents of this library here. So this is unistd.h, I don't know, universal standard, or something like that. And this is what gives us this "write" function that we're using right there. [00:01:34] Main is essentially a function that returns nothing. So, C is a type check language, you do need to actually explicitly spell out every single type that you're saying here. So you do always need to start by saying, what is the type of my function's return value? So in the case of main, we're saying void because we're basically saying main is not returning anything. [00:01:57] -If we wanted main to return an integer or something, then instead of void, we would say [INAUDIBLE] here. Yeah, then we have the list of arguments. So in this case, we're saying main doesn't take any arguments. And then, basically, this write function, which is our 1 single function call here, the number 1 here means we're gonna write to standard out. +If we wanted main to return an integer or something, then instead of void, we would say "int" here. Yeah, then we have the list of arguments. So in this case, we're saying main doesn't take any arguments. And then, basically, this write function, which is our 1 single function call here, the number 1 here means we're gonna write to standard out. [00:02:14] If you gave it the number 2, that would mean write to standard error. So these are hard-coded constants, you could import a file to actually use a named constant instead of a hardcoded integer here. But this one is so hard-coded that it's actually pretty universal that you can just write 1. @@ -29,10 +29,10 @@ If you gave it the number 2, that would mean write to standard error. So these a And also, one of the things that we're gonna see throughout this course is that actually in C, you don't always see in idiomatic C code necessarily people using constants as much as you might in other languages. For example, it is actually kind of common to see people use the number 1 instead of true. [00:02:47] -C is maybe the original language that embraces truthiness, among other things. And they actually do not have, or at least the original versions of CF. I think there might be some C compilers that support this today. But it's still very common to see people just instead of writing out T-R-U-E, they'll just write 1, cuz it's more concise and C treats them essentially the same way. +C is maybe the original language that embraces truthiness, among other things. And they actually do not have, or at least the original versions of C. I think there might be some C compilers that support this today. But it's still very common to see people just instead of writing out T-R-U-E, they'll just write 1, cuz it's more concise and C treats them essentially the same way. [00:03:08] -So then we, of course, have the string Hello, World. And the 13 here is actually the length of the string. So when you're calling the right function, you need to not only give it the string, but you also need to tell it what the length of the string is, or at least how much of the string you want to print. +So then we, of course, have the string Hello, World. And the 13 here is actually the length of the string. So when you're calling the "write" function, you need to not only give it the string, but you also need to tell it what the length of the string is, or at least how much of the string you want to print. [00:03:20] So in this case, when we're doing a hard-coded string like this, of course, the length is really obvious. But if we were using a variable there, that last argument would allow us to say, well, I don't wanna print the entire string, I wanna print a subset of the string. @@ -56,7 +56,7 @@ So this right here, this is essentially a section of the final compiled binary. So, if you ever imagine, if you compile a single standalone binary that runs Hello, World, at some point in those bytes has to be the actual string Hello, World. It needs to know how to actually print out that string. And so those actually do get stored in a particular section of the binary. [00:05:03] -So that's one section. The C compiler is gonna compile down the equivalent assembly, it'll take care of putting that in a different section for you. Even though, when we actually wrote our C code, we wrote that string Hello, World in the middle of the main function. The compiler is gonna say, nah, I know that that goes in a separate sort of constant section. +So that's one section. The C compiler is gonna compile down the equivalent assembly, it'll take care of putting that in a different section for you. Even though, when we actually wrote our C code, we wrote that string Hello, World in the middle of the main function. The compiler is gonna say, nah, I know that that goes in a separate sort of constants section. [00:05:21] LC0 is basically local constant number 0, [LAUGH] that's what that abbreviation is for. So again, the compiler is sort of gonna generate automatic names for things in the actual binary. This offset, flat thing is basically saying, at this point in the program, we wanna go load from that local constant, that section of the binary. @@ -65,22 +65,22 @@ LC0 is basically local constant number 0, [LAUGH] that's what that abbreviation This part right here, this is the actual body of the main function. And this basically corresponds to the exact call to write(1, "Hello, World!", 13). So this one function call actually compiles to four different assembly instructions. And actually, believe it or not, I have alighted some other instructions. [00:06:04] -If you actually look at the real assembly for main, there's some other boilerplate on either side of this for setting up meeting itself. But basically JMP, right, essentially means there is going to be, somewhere else in your binary, a function called write, which is gonna be compiled in from that unit STD library that we imported. +If you actually look at the real assembly for main, there's some other boilerplate on either side of this for setting up main itself. But basically JMP, right, essentially means there is going to be, somewhere else in your binary, a function called write, which is gonna be compiled in from that unit STD library that we imported. [00:06:23] And JMP is basically, jump over there, which means it's basically like a go to. It's go over there and continue running those assembly instructions right there. Before we jump over there, assembly actually will do a little bit of prep work with these other things. So you can see the 1 here where mov to edi, that 1, this offset flat thing was the Hello, World, and then of course there's the 13. [00:06:44] -So essentially what these four instructions are doing, there's one per argument, is each of them is sort of preparing the state of the processor for executing the right function. So you can think of these as sort of like they're writing to global variables. And then when you jump to this other function, the processor's gonna be, cool, I expected these global variables to have already been populated, I'm just gonna go ahead and read them. +So essentially what these four instructions are doing, there's one per argument, is each of them is sort of preparing the state of the processor for executing the "write" function. So you can think of these as sort of like they're writing to global variables. And then when you jump to this other function, the processor's gonna be, cool, I expected these global variables to have already been populated, I'm just gonna go ahead and read them. [00:07:04] So these mov instructions are essentially saying, set these CPU memory slots, these are called registers, it's the lowest level of memory. So every CPU has a hard-coded number of registers. They're essentially, imagine if you had a certain fixed hard-coded number of global mutable variables that you could use to have your functions talk to each other. [00:07:23] -I know, assembly language is read, they're almost great, that's kind of what registers are. So basically, this right function which comes from that unit STD library, that's actually provided by the operating system. So I don't need to mpm install anything or an equivalent to that. These libraries are basically just kind of built into the OS in the same way that, in JavaScript you have the math is built-in. +I know, assembly language is rad, they're almost great, that's kind of what registers are. So basically, this "write" function which comes from that unit STD library, that's actually provided by the operating system. So I don't need to npm install anything or an equivalent to that. These libraries are basically just kind of built into the OS in the same way that, in JavaScript you have the Math is built-in. [00:07:46] -You can say math.random, you don't need to go install a library to get that. +You can say Math.random, you don't need to go install a library to get that. >> Speaker 2: If there's a second constant, where would it be stored? >> Richard Feldman: If there's a second constant, it would also be stored in a similar way. Basically what you would see is, you would see a second section like this. @@ -109,7 +109,7 @@ They might have just been like, yeah, I don't know, global variables, start runn [00:10:01] ->> Speaker 4: So the right function that we're importing, that's tapping into an OS API and not a C standard library? +>> Speaker 4: So the write function that we're importing, that's tapping into an OS API and not a C standard library? >> Richard Feldman: Yeah, so the C standard library, generally, is your way of accessing OS level APIs. There's a little bit of a distinction here between Linux and macOS. I don't wanna get too far in the weeds on this, but there's this thing called syscalls. [00:10:25] @@ -119,10 +119,10 @@ So one of the assembly instructions you can do is you can say, run this syscall. It's like, hey, go to syscall number 17, which corresponds to writing just standard out or whatever. The reason that, for example, in the case of macOS, these are not actually exposed to the programmer. Technically, if you want, I mean, you can make whatever bytes you want go in the binary. [00:10:59] -You can be like, macOS uses 17 to mean, right, to stand it out. But macOs actually officially says, do not do that. Don't compile to hard-coded syscalls because we're gonna change what those numbers mean. So you have to, if you wanna write a correct future proof macOS binary, that's gonna work with future releases of macOS. +You can be like, macOS uses 17 to mean "Write to stand it out." But macOS actually officially says, do not do that. Don't compile to hard-coded syscalls because we're gonna change what those numbers mean. So you have to, if you wanna write a correct future proof macOS binary, that's gonna work with future releases of macOS. [00:11:16] -They require you to use the C standard library, which they feel free to change every time they release a new version of macOS. There's also dynamic linking, which we're not gonna get into either. But basically the way that they do that is they can say, okay, if you are calling, if you're using this as the lowest level primitive where you call right, and that's all there is to it. +They require you to use the C standard library, which they feel free to change every time they release a new version of macOS. There's also dynamic linking, which we're not gonna get into either. But basically the way that they do that is they can say, okay, if you are calling, if you're using this as the lowest level primitive where you call write, and that's all there is to it. [00:11:36] You're not actually hard-coding the syscalls, then they can feel free to change what those numbers mean and sort of mess around with those. Linux actually does guarantee that. So if this were a course on Linux C, we could actually go one step further and say, at this point we don't do a jump to write, we actually do even more instructions ending in a syscall to do the write directly. @@ -146,7 +146,7 @@ So this is a really cool example, I think, of the types of strategies that we us Cuz remember, PDP 11, right? [LAUGH] 120, whatever, kilobytes of RAM. 120 kilohertz processor, single core, yeah, you didn't wanna waste any cycles back then on things like garbage collection and objects and whatnot. So it is literally unbeatably fast. You can make a programming language that's more ergonomic than C, but you cannot make a programming language that, at least for this use case, is faster than C, it's literally not possible. [00:14:01] -So now we are as close to the middle as you can get, congratulations. All right, yeah, and also, the right function could be doing stuff that could get faster. But again, if the operating system, as macOS and Windows do, is saying, this is what we're providing you. We don't have as programmers the ability to make that go faster unless you wanna fork the operating system kernel, then you can go in and rebuild the operating system. +So now we are as close to the metal as you can get, congratulations. All right, yeah, and also, the write function could be doing stuff that could get faster. But again, if the operating system, as macOS and Windows do, is saying, this is what we're providing you. We don't have as programmers the ability to make that go faster unless you wanna fork the operating system kernel, then you can go in and rebuild the operating system. [00:14:25] Okay, fine, but we're not generally doing that, [LAUGH] we're making stuff that runs in the operating system. diff --git a/en-US/2025-06-09-c-fundamentals/2-hello-world-in-c.vtt b/en-US/2025-06-09-c-fundamentals/2-hello-world-in-c.vtt index b6cb433f..173fad40 100644 --- a/en-US/2025-06-09-c-fundamentals/2-hello-world-in-c.vtt +++ b/en-US/2025-06-09-c-fundamentals/2-hello-world-in-c.vtt @@ -126,7 +126,7 @@ the different parts of what we got here. 27 00:01:14.845 --> 00:01:19.338 -So essentially, this pound include here, +So essentially, this "#include" here, we're gonna talk about what the pound sign 28 @@ -150,7 +150,7 @@ something like that. 32 00:01:31.114 --> 00:01:34.647 -And this is what gives us this right +And this is what gives us this "write" function that we're using right there. 33 @@ -193,7 +193,7 @@ something, then instead of void, 41 00:02:00.722 --> 00:02:02.127 -we would say [INAUDIBLE] here. +we would say "int" here. 42 00:02:02.127 --> 00:02:05.385 @@ -270,7 +270,7 @@ embraces truthiness, among other things. 57 00:02:50.623 --> 00:02:54.638 And they actually do not have, or -at least the original versions of CF. +at least the original versions of C. 58 00:02:54.638 --> 00:02:58.543 @@ -303,7 +303,7 @@ the length of the string. 64 00:03:13.166 --> 00:03:16.468 -So when you're calling the right function, +So when you're calling the "write" function, you need to not only give it the string, 65 @@ -511,7 +511,7 @@ The compiler is gonna say, nah, 107 00:05:18.611 --> 00:05:21.609 I know that that goes in a separate -sort of constant section. +sort of constants section. 108 00:05:21.609 --> 00:05:24.877 @@ -577,7 +577,7 @@ for main, there's some other boilerplate 121 00:06:08.347 --> 00:06:10.994 on either side of this for -setting up meeting itself. +setting up main itself. 122 00:06:10.994 --> 00:06:15.328 @@ -635,7 +635,7 @@ preparing the state of the processor for 133 00:06:51.578 --> 00:06:53.170 -executing the right function. +executing the "write" function. 134 00:06:53.170 --> 00:06:55.894 @@ -683,7 +683,7 @@ have your functions talk to each other. 143 00:07:23.500 --> 00:07:26.603 -I know, assembly language is read, +I know, assembly language is rad, they're almost great, 144 @@ -692,7 +692,7 @@ that's kind of what registers are. 145 00:07:28.462 --> 00:07:32.075 -So basically, this right function which +So basically, this "write" function which comes from that unit STD library, 146 @@ -702,7 +702,7 @@ by the operating system. 147 00:07:34.626 --> 00:07:37.986 -So I don't need to mpm install anything or +So I don't need to npm install anything or an equivalent to that. 148 @@ -713,11 +713,11 @@ built into the OS in the same way that, 149 00:07:43.632 --> 00:07:46.885 in JavaScript you have -the math is built-in. +the Math is built-in. 150 00:07:46.885 --> 00:07:50.197 -You can say math.random, you don't need +You can say Math.random, you don't need to go install a library to get that. 151 @@ -918,7 +918,7 @@ everything's a global, [LAUGH] yeah. 192 00:10:01.402 --> 00:10:05.606 >> Speaker 4: So -the right function that we're importing, +the write function that we're importing, 193 00:10:05.606 --> 00:10:11.013 @@ -1003,12 +1003,12 @@ you want go in the binary. 210 00:10:59.222 --> 00:11:02.479 -You can be like, macOS uses 17 to mean, -right, to stand it out. +You can be like, macOS uses 17 to mean +"Write to stand it out." 211 00:11:02.479 --> 00:11:05.454 -But macOs actually officially says, +But macOS actually officially says, do not do that. 212 @@ -1053,7 +1053,7 @@ they can say, okay, if you are calling, 220 00:11:31.546 --> 00:11:35.431 if you're using this as the lowest level -primitive where you call right, and +primitive where you call write, and 221 00:11:35.431 --> 00:11:36.838 @@ -1280,7 +1280,7 @@ it's literally not possible. 268 00:14:01.010 --> 00:14:05.110 -So now we are as close to the middle +So now we are as close to the metal as you can get, congratulations. 269 @@ -1289,7 +1289,7 @@ All right, yeah, and also, 270 00:14:07.341 --> 00:14:11.732 -the right function could be doing +the write function could be doing stuff that could get faster. 271 diff --git a/en-US/2025-06-09-c-fundamentals/20-socket-exercise.txt b/en-US/2025-06-09-c-fundamentals/20-socket-exercise.txt index 86d250a5..586dedb6 100644 --- a/en-US/2025-06-09-c-fundamentals/20-socket-exercise.txt +++ b/en-US/2025-06-09-c-fundamentals/20-socket-exercise.txt @@ -1,11 +1,11 @@ [00:00:00] ->> Richard Feldman: All right, now you might notice that we have some more includes than last time. So one of the clues that I want to kinda shout out here is this is how old [LAUGH] C is. This is arpa/inet.h. So, the ARPANET, these like the original internet, like the precursor to the worldwide web, this is how old school this stuff was. +>> Richard Feldman: All right, now you might notice that we have some more includes than last time. So one of the clues that I want to kinda shout out here is this is how old [LAUGH] C is. This is arpa/inet.h. So, the ARPANET, these like the original internet, like the precursor to the world wide web, this is how old school this stuff was. [00:00:18] -Like they were using C in fact. On the arpa/inet. [LAUGH] that's how old this stuff is. And guess what? It still works in 2025. Very cool, all right. So as usual, we're just gonna start by building and running the program. There we go. And now it just says listening on port 8080. +Like they were using C in fact on the ARPANET. [LAUGH] that's how old this stuff is. And guess what? It still works in 2025. Very cool, all right. So as usual, we're just gonna start by building and running the program. There we go. And now it just says listening on port 8080. [00:00:37] -So, let's see what is actually happening on port 8080. So, if I go to local host 80 80, it says, hey, this is the root /page. There's nothing here except a blog. Now, if you may recall what was actually happening here is where was that? Index.html, right? So, this is the root/page. +So, let's see what is actually happening on port 8080. So, if I go to localhost:8080, it says, hey, this is the root / page. There's nothing here except a blog. Now, if you may recall what was actually happening here is where was that? Index.html, right? So, this is the root / page. [00:00:58] There's nothing here except a blog. Hello everyone. I'm gonna just do that, not gonna restart the server. I just saved that file and we go back here, refresh the page, and bam, there it is. So that is what we've built up to today [LAUGH]. We've got a real static HTTP server. @@ -14,13 +14,13 @@ There's nothing here except a blog. Hello everyone. I'm gonna just do that, not We're gonna make it better in the next and final part of the course. But, but hey, it actually works, and it's not actually that much C code. Like if we look at this file, this is only like 220 lines of C code. Now granted, there's a lot of edge cases we're not handling here. [00:01:26] -This actually doesn't support images yet. We're going to get to that in the next section, but it's pretty impressive. Like that this is all it takes to build a really, really high-performance, like C web server. Yes, some of the APIs are a little bit funky. Yes, we're doing a lot of weird stomping all over memory kind of tech. +This actually doesn't support images yet. We're going to get to that in the next section, but it's pretty impressive. Like that this is all it takes to build a really, really high-performance, like C web server. Yes, some of the APIs are a little bit funky. Yes, we're doing a lot of weird stomping all over memory kind of techniques in here, but if you want to get down to it and like really like get close to the operating system, this is what that looks like, all right. [00:01:40] -Techniques in here, but if you want to get down to it and like really like get close to the operating system, this is what that looks like, all right. Now I do want to notice, sorry, that was from earlier. We are getting a number of HTTP 500 internal server errors here. +Now I do want to note this, sorry, that was from earlier. We are getting a number of HTTP 500 internal server errors here. [00:01:57] -Now this might kind of surprise you because on the one hand, well, first of all, I didn't actually go over the. Part of the code where we are, in some cases we're turning at 500, so we'll look at that in a second. But also you might be, yeah, what's going on with that? +Now this might kind of surprise you because on the one hand, well, first of all, I didn't actually go over the. Part of the code where we are, in some cases we're returning 500, so we'll look at that in a second. But also you might be, yeah, what's going on with that? [00:02:07] Because, I mean, clearly the browser doesn't think there was an error like this was, it's just like worked. So what's going on there? So, if I refresh this page, I might notice, what's that little thing down there? Let me zoom in for you. This is something that we don't actually have right now. @@ -32,7 +32,7 @@ Support for images includes support for the favicon. So, favicon is a fun little You might be wondering, like, why is it printing so many of those? Like, if I refresh the page, I get two, 500 internal server errors, not one. We'll talk about that in a second. All right, so going through this code in part five exercise. This is all just like exactly the same stuff that we went on the slides, except now it's all sort of spread out here. [00:03:08] -We're doing the handle request thing. This is our little helper function that does take the request and the socket and like calls to path on it. This is basically just like I just split out a helper function, so we can sort of isolate the request quest handling code in here, just for code organization. +We're doing the handle request thing. This is our little helper function that does take the request and the socket and like calls to_path on it. This is basically just like I just split out a helper function, so we can sort of isolate the request handling code in here, just for code organization. [00:03:21] But otherwise the same exact stuff we did in the slides. We are doing a little like, okay, if I open this path and I get file descriptor is -1. Then we want to handle the case where it's a 404 differently and not just like, always do a 500. @@ -45,22 +45,22 @@ Down here, again, we're just like printf, if we fail to get the stats on this th [00:04:20] And what we want to be doing instead is just actually sending it to the socket. ->> Richard Feldman: All right, let's go through the solution. Okay, so a bunch of the stuff unchanged from previous like two path works the same way as before, fundamentally. Handle requests is our little helper function here for just dealing with the request stuff. +>> Richard Feldman: All right, let's go through the solution. Okay, so a bunch of the stuff unchanged from previous like to_path works the same way as before, fundamentally. Handle requests is our little helper function here for just dealing with the request stuff. [00:04:43] -The theme here is that we've got all these like different error scenarios that we want to handle properly. So for example, in this case, we've got HTTP 400 bad requests. So what does that mean? This means that when we called to path, to path, returned null. So here we've essentially done that same kind of C style error handling. +The theme here is that we've got all these like different error scenarios that we want to handle properly. So for example, in this case, we've got HTTP 400 bad requests. So what does that mean? This means that when we called to_path, to_path, returned null. So here we've essentially done that same kind of C style error handling. [00:05:01] -That we've seen in all these PIs we've been using, where basically you may recall, if we didn't have enough space to write this thing, meaning that we got a weird request that didn't have like enough space to write this thing. Or if we got something that didn't have the space where we expected it, like the file ended before we hit the spaces. +That we've seen in all these APIs we've been using, where basically you may recall, if we didn't have enough space to write this thing, meaning that we got a weird request that didn't have like enough space to write this thing. Or if we got something that didn't have the space where we expected it, like the file ended before we hit the spaces. [00:05:20] -In either case, that means this is an invalid request, and two path would have returned null. And here we're just basically doing that same exact error handling case where we're like, yeah, let's see if what this function returned gave us an error code, in other words, a null address here, or a null pointer. +In either case, that means this is an invalid request, and to_path would have returned null. And here we're just basically doing that same exact error handling case where we're like, yeah, let's see if what this function returned gave us an error code, in other words, a null address here, or a null pointer. [00:05:36] And basically, we're like, yeah, okay, now we need to propagate this error properly. So how are we going to do this? Well, we're gonna send this bad request header back to the browser and essentially say, okay, I'm gonna do a write and write takes as its first argument, the file descriptor. [00:05:51] -So, this is gonna be socket FD. And then basically if we want, we can do like the know, sterling of that thing. Or if we wanna be like a little bit fancier about it, we can kind of put this up here and say like const char star, error 400 or something like that equals that. +So, this is gonna be socket_fd. And then basically if we want, we can do like the, you know, strlen of that thing. Or if we wanna be like a little bit fancier about it, we can kind of put this up here and say like const char star, error 400 or something like that equals that. [00:06:11] And then down here, we can just do strlen of that one. There you go. So, this is basically a pretty straightforward pattern for just sending like a 400 error. If we have something that we are dealing with a lot, like we are with 500 errors, we might even wanna make a little helper function, which I'm gonna do in a sec, to just like do this right for me. @@ -72,7 +72,7 @@ Okay, next one here. This one's actually kind of cool because it's pretty easy t And it's like, well, hang on a sec. That's like, Foo is not a thing, so it's like cool 404 Not Found for that. Now, by the way, I'm gonna not touch my keyboard for a second, and you might be a little bit surprised that even though. I am not touching my keyboard. [00:07:01] -All right, I might need to, sorry, I might need to do that over again. Okay, I'm gonna local host for yeah /foo not touching the keyboard. And yet we're still getting like 404 coming in. So what's going on there? Why did we just get a 404 on my hands weren't even on the keyboard. +All right, I might need to, sorry, I might need to do that over again. Okay, I'm gonna localhost for yeah /foo not touching the keyboard. And yet we're still getting like 404 coming in. So what's going on there? Why did we just get a 404 while my hands weren't even on the keyboard. [00:07:17] Does anyone have any guesses as to what's going on there? @@ -80,19 +80,19 @@ Does anyone have any guesses as to what's going on there? >> Richard Feldman: Yes, this is, this is easier to tell if you use Wget here, and Wget is basically gonna actually, like, tell us what it's doing. I need to actually be running the server. So run this on a different one. [00:07:38] -It's basically, hey, HTTP request sent a rating response, no data received retrying, retrying, retrying, retrying. And the reason for that is that I'm printing out 404, to standard, out, but I'm not actually telling the server anything. So the server is not getting any response here. It's just like, hey, hello. +It's basically, hey, HTTP request sent a awaiting response, no data received retrying, retrying, retrying, retrying. And the reason for that is that I'm printing out 404, to standard, out, but I'm not actually telling the server anything. So the server is not getting any response here. It's just like, hey, hello. [00:07:53] What's going on? And it's just like, times out. It's like, well, hang on, let me try again. Hang on, let me try again. So, the browser is the same thing, it just doesn't have as much of it. Delay as Wget does in between retry attempts. But not to worry, because once we actually like respond with this, then we're gonna be okay. [00:08:08] -So, I'm going to basically just do the same like pattern that I did here. So, this is going to be 404 Not Found, and I'm just gonna follow exactly the same pattern that I did back there, where I'm just gonna write to but instead of error 404, it's gonna be, sorry, instead of error 400, it's gonna be 404. +So, I'm going to basically just do the same like pattern that I did here. So, this is going to be 404 Not Found, and I'm just gonna follow exactly the same pattern that I did back there, where I'm just gonna write to this, but instead of error 404, it's gonna be, sorry, instead of error 400, it's gonna be 404. [00:08:25] -So, we're gonna do that and then we do the same thing over here with 500, okay. And now, it's gone there. Yeah, I didn't actually define the error 500. Let's go ahead and do that. Okay, there we go, cool. I'm using Zed's fancy autocomplete there, so I to save myself some typing there, but you get the idea 400, 404, 500, etc. +So, we're gonna do that and then we do the same thing over here with 500, okay. And now, it's gone there. Yeah, I didn't actually define the error 500. Let's go ahead and do that. Okay, there we go, cool. I'm using Zed's fancy autocomplete there, so I had to save myself some typing there, but you get the idea 400, 404, 500, etc. [00:08:48] -And then basically we're just gonna write these here. Okay, so now when I restart the server, now we should get something much more semantically familiar. If I go to localhost.com, port 88/foo, we get, hey, page can't be found because the browser actually knows when I get a 404 back. +And then basically we're just gonna write these here. Okay, so now when I restart the server, now we should get something much more semantically familiar. If I go to localhost.com, port 8080/foo, we get, hey, page can't be found because the browser actually knows when I get a 404 back. [00:09:04] Here's what I do. I display, you know, HTTP error 404 and good stuff like that. And now we are not actually going to see all these things spamming us locally, because when the browser gets a 404 it knows what to do with that. It's like, yeah, got it. @@ -101,28 +101,28 @@ Here's what I do. I display, you know, HTTP error 404 and good stuff like that. This is a 404 error. I'm very familiar with these. I don't need to retry because we actually did send it a response in that scenario now. All right, looking good. So that's definitely an improvement. Let's keep going. So, at this point, we might notice a pattern here where it's like, okay, this one's gonna be a 500 error. [00:09:34] -This is like if fsat failed. So, this means that like we were able to open the file because if we weren't able to open the file, then we would have 404. I forgot to mention, by the way, this is another beautiful C error-handling pattern. So, if fd=-1, that tells us it's an error, but it doesn't tell us what type of error we have. +This is like if fstat failed. So, this means that like we were able to open the file because if we weren't able to open the file, then we would have 404. I forgot to mention, by the way, this is another beautiful C error-handling pattern. So, if fd=-1, that tells us it's an error, but it doesn't tell us what type of error we have. [00:09:52] -That is the open function will set, will mutate this magical global variable called errno. This is not something that we wrote. This is just a magical global. And the way that errorno works, it's sort of like error number is when you call a function that can error in a particular way. +That is the open function will set, will mutate this magical global variable called errno. This is not something that we wrote. This is just a magical global. And the way that errno works, it's short of like error number is when you call a function that can error in a particular way. [00:10:10] -The way that you check whether this function failed was look at it as a string value and see if it was negative one. If it was negative one, then you go look at errorno before calling another function that does that, or else, you're gonna be in big trouble. +The way that you check whether this function failed was look at its return value and see if it was negative one. If it was negative one, then you go look at errno before calling another function that does that, or else, you're gonna be in big trouble. [00:10:19] -Because it's gonna stop all over it. And then in that magical little window between when you called one of these functions and you called another one, errno will be set to whatever the most recent way that one of these failed was. And this will tell you what the actual error was. +Because it's gonna stomp all over it. And then in that magical little window between when you called one of these functions and you called another one, errno will be set to whatever the most recent way that one of these failed was. And this will tell you what the actual error was. [00:10:33] -And ENOENT, and I'm not sure why exactly that. I remember at some point I knew the history behind why it was called that. But this is like, basically means file was not found. So, if you ever use no JS, you actually can see this. Sometimes you see, like, the console, like an error, like, no end, or something like that. +And ENOENT, and I'm not sure why exactly that. I remember at some point I knew the history behind why it was called that. But this is like, basically means file was not found. So, if you ever use Node.js, you actually can see this. Sometimes you see, like, the console, like an error, like, ENOENT, or something like that. [00:10:48] -And that's because no JS is sort of uncritically passed along the the like C style error from this thing. So, if it's one of those errors, then we're like, okay, 404, meaning not found. So, this bit basically means like we attempted to open that path. So in this case, when I went to local host 8080/foo, we'd be coming through here. +And that's because Node.js is sort of uncritically passed along the the like C style error from this thing. So, if it's one of those errors, then we're like, okay, 404, meaning not found. So, this basically means like we attempted to open that path. So in this case, when I went to localhost:8080/foo, we'd be coming through here. [00:11:08] -The path would be foo/index.html. But since I don't have a directory called foo or a index.html within it, when I try to open that, this fails. FD is negative one errorno is set to Eno, end, meaning that it was file not found. And therefore we know to send, backup 404. +The path would be foo/index.html. But since I don't have a directory called foo or a index.html within it, when I try to open that, this fails. FD is negative one errno is set to ENOENT, end, meaning that it was file not found. And therefore we know to send back a 404. [00:11:23] -If it was anything else, like the file was there, it was found, but we couldn't open it, for some strange reason, like a permissions issue, or something, then we're gonna call that an internal server error, and send backup 500. And a lot of these are going to be 500s. +If it was anything else, like the file was there, it was found, but we couldn't open it, for some strange reason, like a permissions issue, or something, then we're gonna call that an internal server error, and send back a 500. And a lot of these are going to be 500s. [00:11:34] Like if we were able to open the file, but fstat on it failed, for whatever reason. Again, 500, internal server error. What happens if we attempted to write to the socket and writing to the socket failed, even though reading the file succeeded again, 500 internal server error. Now, there are so many of these things that at some point you start to be like, okay, maybe rather than, like, duplicating all of this write logic over and over. @@ -131,16 +131,16 @@ Like if we were able to open the file, but fstat on it failed, for whatever reas Maybe I should just actually extract a little helper function for this, which I think is, like, perfectly reasonable. Let's say I wanted to just make a little helper function for this. One of the things we would probably wanna do is even though we're not using it here, is I would actually like to return, like, pass along the return value of the write. [00:12:12] -So that's an size t. And I'll just call this like write 500. So, it takes socket, int, socket, good. And then we need the actual like, sorry, this is the 500, so we actually don't need that. We know that. So basically, what I'm gonna do is I'm gonna say return, whatever right return. +So that's an ssize_t. And I'll just call this like write_500. So, it takes socket, int, socket_fd, good. And then we need the actual like, sorry, this is the 500, so we actually don't need that. We know that. So basically, what I'm gonna do is I'm gonna say return, whatever write returns. [00:12:34] -So that way if we do decide we want to handle that error, we have the ability to, and then it's just gonna be this exact thing. So now that we have. I can replace this with that socket-fd, okay, great. And then now every time I see one of these things, I can just do a nice little one of those. +So that way if we do decide we want to handle that error, we have the ability to, and then it's just gonna be this exact thing. So now that we have. I can replace this with that socket_fd, okay, great. And then now every time I see one of these things, I can just do a nice little one of those. [00:12:54] Well, yeah, I guess we, right. We do want to early return when that happens. So, we wanna like exit instead of just printing this one's already like, returning negative one. Yeah, I guess if, okay, never mind. We do want to return negative one to indicate to the caller that we that we failed. [00:13:09] -So that's fine. Okay, so we can do that. Or we could have write 500 return negative one and just return that. But I think it's probably more idiomatic to just like, propagate the error in case we do want to handle it separately, like maybe writing it to a log file or something like that. +So that's fine. Okay, so we can do that. Or we could have write_500 return negative one and just return that. But I think it's probably more idiomatic to just like, propagate the error in case we do want to handle it separately, like maybe writing it to a log file or something like that. [00:13:22] But yeah, I mean, all of these being 500s, now we have our little helper function. Nice and easy and there we go, great. Now you might notice that over in this section of the code, like this is a actual main, like before we're doing the handle request stuff. @@ -149,7 +149,7 @@ But yeah, I mean, all of these being 500s, now we have our little helper functio We do have error handling around all these things, which we didn't talk about in the slides. These do not actually send a 500 error. Can anyone think of why we don't do that? >> Speaker 3: We didn't even get to start the server. >> Richard Feldman: Yeah. ->> Speaker 3: Probably the most thing. +>> Speaker 3: Probably we're not even listening. [00:13:46] @@ -160,28 +160,28 @@ That's the only point where we can, there's one more of these, fine. Let's see i [00:14:24] All right, I guess I need to ERR_404, ERR_413. Content too large. ->> Richard Feldman: Okay, and the right, great. Okay, and then I guess we actually so in this case, we don't necessarily need to early return, because we might want to just keep handling further requests. Just because this one was too big, that's no big deal. +>> Richard Feldman: Okay, and the write, great. Okay, and then I guess we actually so in this case, we don't necessarily need to early return, because we might want to just keep handling further requests. Just because this one was too big, that's no big deal. [00:15:00] But, yeah, this is basically like the difference between error handling when we don't have an active connection and don't have a browser connection that we can like actually send the response back to. And when we're just still kind of like starting up and like trying to start up the server. [00:15:13] -So, if any of these fail, like for example, it's pretty easy to induce, say, like, addresses and use. So, if I leave this server running and then I try to, like, do this again. Was around 5, yeah examples exercise yeah. So, it says, like, bind failed address and use. +So, if any of these fail, like for example, it's pretty easy to induce, say, like, address is in use. So, if I leave this server running and then I try to, like, do this again. Was around 5, yeah examples exercise yeah. So, it says, like, bind failed address in use. [00:15:33] Would be a nicer example to give. But yeah, this is the way you can actually get this thing to not even make it to the while loop. The infinite loop, because it's like, yeah, bind failed. So, we're done, okay. Now, as cool as this is so we got our 404 here. [00:15:48] -If we go to root, that works. I can even like follow links cause this takes us, that changes the URL to /blog, which also works cause we have /blog/inject.html. All of that works great. But we are missing an important piece here, which is that I have strategically chosen to make these things have no images or CSS, or JavaScript whatsoever. +If we go to root, that works. I can even like follow links cause this takes us, that changes the URL to /blog, which also works cause we have /blog/index.html. All of that works great. But we are missing an important piece here, which is that I have strategically chosen to make these things have no images or CSS, or JavaScript whatsoever. [00:16:05] And the reason that I do that is if let's say, for example, I were taking the front-end master's homepage, which I've actually got right here in a separate tab. This is what our beautiful web server does for the front-end master's homepage. Now we do have one of these images kind of works, but you notice that all the CSS and all the JS and all that stuff. [00:16:21] -It's just totally busted, and also the image is totally busted. This one's a little bit better. That's kind of cool. Everything's horrendous. Why is everything horrendous? Because all we are doing for our requests, or sorry, our response headers is we're just doing HTP 1.1 200, okay. We are not sending a single response header whatsoever, and the browser uses those headers like content types specifically to figure out like how to interpret this thing. +It's just totally busted, and also the image is totally busted. This one's a little bit better. That's kind of cool. Everything's horrendous. Why is everything horrendous? Because all we are doing for our requests, or sorry, our response headers is we're just doing HTTP 1.1 200, okay. We are not sending a single response header whatsoever, and the browser uses those headers like content type specifically to figure out like how to interpret this thing. [00:16:44] -So, if I just send it a bunch of bytes and I say, hey, this is a CSS file, it's not gonna just be like, well that is a dot CSS, I bet it's a CSS file. No, it says like, no, you need to tell me in a header how I'm supposed to interpret these bytes that you've sent me. +So, if I just send it a bunch of bytes and I say, hey, this is a CSS file, it's not gonna just be like, well that ends in .CSS, I bet it's a CSS file. No, it says like, no, you need to tell me in a header how I'm supposed to interpret these bytes that you've sent me. [00:16:56] And right now we're not doing that at all. When it comes to the bare HTML, it's gonna be fine with that. But that's pretty much where it draws the line. So essentially, what we need to do is we need to start actually sending response headers, which is what we're gonna do in the final section of the workshop. diff --git a/en-US/2025-06-09-c-fundamentals/20-socket-exercise.vtt b/en-US/2025-06-09-c-fundamentals/20-socket-exercise.vtt index d811aa44..5659438e 100644 --- a/en-US/2025-06-09-c-fundamentals/20-socket-exercise.vtt +++ b/en-US/2025-06-09-c-fundamentals/20-socket-exercise.vtt @@ -29,16 +29,16 @@ these like the original internet, 7 00:00:15.306 --> 00:00:18.721 -like the precursor to the worldwide web, +like the precursor to the world wide web, this is how old school this stuff was. 8 00:00:18.721 --> 00:00:20.587 -Like they were using C in fact. +Like they were using C in fact 9 00:00:20.587 --> 00:00:21.588 -On the arpa/inet. +on the ARPANET. 10 00:00:21.588 --> 00:00:24.927 @@ -77,8 +77,8 @@ happening on port 8080. 18 00:00:40.272 --> 00:00:44.602 -So, if I go to local host 80 80, -it says, hey, this is the root /page. +So, if I go to localhost:8080, +it says, hey, this is the root / page. 19 00:00:44.602 --> 00:00:46.140 @@ -98,7 +98,7 @@ Index.html, right? 23 00:00:56.917 --> 00:00:58.721 -So, this is the root/page. +So, this is the root / page. 24 00:00:58.721 --> 00:01:01.270 @@ -177,11 +177,11 @@ are a little bit funky. 40 00:01:38.311 --> 00:01:40.565 Yes, we're doing a lot of weird -stomping all over memory kind of tech. +stomping all over memory kind of 41 00:01:40.565 --> 00:01:45.269 -Techniques in here, but if you want to +techniques in here, but if you want to get down to it and like really like get 42 @@ -191,7 +191,7 @@ this is what that looks like, all right. 43 00:01:49.910 --> 00:01:52.653 -Now I do want to notice, +Now I do want to note this, sorry, that was from earlier. 44 @@ -212,7 +212,7 @@ I didn't actually go over the. 47 00:02:00.978 --> 00:02:03.945 Part of the code where we are, -in some cases we're turning at 500, so +in some cases we're returning 500, so 48 00:02:03.945 --> 00:02:05.271 @@ -286,7 +286,7 @@ going to get one of these things, 63 00:02:45.873 --> 00:02:48.553 then by default, what you're going -to get is some sort of error. +to get is some short of error. 64 00:02:48.553 --> 00:02:51.105 @@ -328,7 +328,7 @@ does take the request and the socket and 72 00:03:14.950 --> 00:03:16.379 -like calls to path on it. +like calls to_path on it. 73 00:03:16.379 --> 00:03:18.883 @@ -337,7 +337,7 @@ split out a helper function, so we can 74 00:03:18.883 --> 00:03:21.957 -sort of isolate the request quest handling +sort of isolate the request handling code in here, just for code organization. 75 @@ -429,7 +429,7 @@ let's go through the solution. 93 00:04:32.950 --> 00:04:37.848 Okay, so a bunch of the stuff unchanged -from previous like two path works the same +from previous like to_path works the same 94 00:04:37.848 --> 00:04:39.879 @@ -464,8 +464,8 @@ So what does that mean? 101 00:04:53.640 --> 00:04:57.221 -This means that when we called to path, -to path, returned null. +This means that when we called to_path, +to_path, returned null. 102 00:04:57.221 --> 00:05:01.291 @@ -474,7 +474,7 @@ same kind of C style error handling. 103 00:05:01.291 --> 00:05:05.479 -That we've seen in all these PIs we've +That we've seen in all these APIs we've been using, where basically you may 104 @@ -504,7 +504,7 @@ that means this is an invalid request, and 109 00:05:24.044 --> 00:05:26.039 -two path would have returned null. +to_path would have returned null. 110 00:05:26.039 --> 00:05:29.985 @@ -547,12 +547,12 @@ the file descriptor. 118 00:05:51.326 --> 00:05:53.040 -So, this is gonna be socket FD. +So, this is gonna be socket_fd. 119 00:05:53.040 --> 00:05:58.245 And then basically if we want, we can do -like the know, sterling of that thing. +like the, you know, strlen of that thing. 120 00:05:58.245 --> 00:06:02.352 @@ -654,7 +654,7 @@ I might need to do that over again. 141 00:07:05.153 --> 00:07:09.250 -Okay, I'm gonna local host for +Okay, I'm gonna localhost for yeah /foo not touching the keyboard. 142 @@ -668,7 +668,7 @@ So what's going on there? 144 00:07:13.572 --> 00:07:17.216 -Why did we just get a 404 on my +Why did we just get a 404 while my hands weren't even on the keyboard. 145 @@ -701,7 +701,7 @@ So run this on a different one. 151 00:07:38.117 --> 00:07:40.411 It's basically, hey, -HTTP request sent a rating response, +HTTP request sent a awaiting response, 152 00:07:40.411 --> 00:07:42.763 @@ -776,7 +776,7 @@ I'm just gonna follow exactly the same 167 00:08:16.467 --> 00:08:20.834 pattern that I did back there, where I'm -just gonna write to but instead of error +just gonna write to this, but instead of error 168 00:08:20.834 --> 00:08:25.429 @@ -808,7 +808,7 @@ Okay, there we go, cool. 174 00:08:40.696 --> 00:08:45.453 I'm using Zed's fancy autocomplete there, -so I to save myself some typing there, +so I had to save myself some typing there, 175 00:08:45.453 --> 00:08:48.470 @@ -831,7 +831,7 @@ more semantically familiar. 179 00:08:58.380 --> 00:09:01.116 If I go to localhost.com, -port 88/foo, we get, hey, +port 8080/foo, we get, hey, 180 00:09:01.116 --> 00:09:04.866 @@ -901,7 +901,7 @@ this one's gonna be a 500 error. 195 00:09:34.739 --> 00:09:36.009 -This is like if fsat failed. +This is like if fstat failed. 196 00:09:36.009 --> 00:09:39.596 @@ -950,7 +950,7 @@ This is just a magical global. 206 00:10:01.900 --> 00:10:06.782 -And the way that errorno works, +And the way that errno works, it's sort of like error number is when 207 @@ -961,7 +961,7 @@ error in a particular way. 208 00:10:10.604 --> 00:10:12.998 The way that you check whether this -function failed was look at it as a string +function failed was look at its return 209 00:10:12.998 --> 00:10:14.181 @@ -970,7 +970,7 @@ value and see if it was negative one. 210 00:10:14.181 --> 00:10:17.450 If it was negative one, then you go look -at errorno before calling another function +at errno before calling another function 211 00:10:17.450 --> 00:10:19.802 @@ -979,7 +979,7 @@ you're gonna be in big trouble. 212 00:10:19.802 --> 00:10:21.885 -Because it's gonna stop all over it. +Because it's gonna stomp all over it. 213 00:10:21.885 --> 00:10:24.645 @@ -1018,7 +1018,7 @@ basically means file was not found. 220 00:10:43.077 --> 00:10:45.016 -So, if you ever use no JS, +So, if you ever use Node.js, you actually can see this. 221 @@ -1028,11 +1028,11 @@ the console, like an error, 222 00:10:47.197 --> 00:10:48.747 -like, no end, or something like that. +like, ENOENT, or something like that. 223 00:10:48.747 --> 00:10:53.659 -And that's because no JS is sort +And that's because Node.js is sort of uncritically passed along 224 @@ -1047,13 +1047,13 @@ we're like, okay, 404, meaning not found. 226 00:11:00.418 --> 00:11:03.732 -So, this bit basically means like +So, this basically means like we attempted to open that path. 227 00:11:03.732 --> 00:11:08.031 -So in this case, when I went to local host -8080/foo, we'd be coming through here. +So in this case, when I went to +localhost:8080/foo, we'd be coming through here. 228 00:11:08.031 --> 00:11:09.869 @@ -1070,12 +1070,12 @@ when I try to open that, this fails. 231 00:11:15.761 --> 00:11:20.215 -FD is negative one errorno is set to Eno, +FD is negative one errno is set to ENOENT, end, meaning that it was file not found. 232 00:11:20.215 --> 00:11:23.533 -And therefore we know to send, backup 404. +And therefore we know to send back a 404. 233 00:11:23.533 --> 00:11:26.991 @@ -1090,7 +1090,7 @@ like a permissions issue, or something, 235 00:11:29.970 --> 00:11:33.214 then we're gonna call that an internal -server error, and send backup 500. +server error, and send back a 500. 236 00:11:33.214 --> 00:11:34.670 @@ -1156,15 +1156,15 @@ pass along the return value of the write. 249 00:12:12.883 --> 00:12:16.491 -So that's an size t. +So that's an ssize_t. 250 00:12:16.491 --> 00:12:18.326 -And I'll just call this like write 500. +And I'll just call this like write_500. 251 00:12:18.326 --> 00:12:23.646 -So, it takes socket, int, socket, good. +So, it takes socket, int, socket_fd, good. 252 00:12:23.646 --> 00:12:27.696 @@ -1182,7 +1182,7 @@ We know that. 255 00:12:30.479 --> 00:12:34.264 So basically, what I'm gonna do is I'm -gonna say return, whatever right return. +gonna say return, whatever write returns. 256 00:12:34.264 --> 00:12:37.667 @@ -1200,7 +1200,7 @@ So now that we have. 259 00:12:41.563 --> 00:12:49.347 -I can replace this with that socket-fd, +I can replace this with that socket_fd, okay, great. 260 @@ -1253,7 +1253,7 @@ Okay, so we can do that. 271 00:13:11.890 --> 00:13:14.170 -Or we could have write 500 return +Or we could have write_500 return negative one and just return that. 272 @@ -1315,7 +1315,7 @@ get to start the server. 284 00:13:45.835 --> 00:13:46.881 >> Richard Feldman: Yeah. ->> Speaker 3: Probably the most thing. +>> Speaker 3: Probably we're not even listening. 285 00:13:46.881 --> 00:13:50.258 @@ -1385,7 +1385,7 @@ Content too large. 299 00:14:41.358 --> 00:14:46.396 -the right, great. +the write, great. 300 00:14:46.396 --> 00:14:51.450 @@ -1432,7 +1432,7 @@ example, it's pretty easy to induce, say, 309 00:15:16.895 --> 00:15:18.198 -like, addresses and use. +like, address is in use. 310 00:15:18.198 --> 00:15:24.156 @@ -1446,7 +1446,7 @@ Was around 5, yeah examples exercise yeah. 312 00:15:31.213 --> 00:15:33.258 So, it says, like, -bind failed address and use. +bind failed address in use. 313 00:15:33.258 --> 00:15:34.888 @@ -1487,7 +1487,7 @@ takes us, that changes the URL to /blog, 321 00:15:53.582 --> 00:15:56.335 which also works cause we -have /blog/inject.html. +have /blog/index.html. 322 00:15:56.335 --> 00:15:57.745 @@ -1561,7 +1561,7 @@ our requests, or sorry, 337 00:16:32.184 --> 00:16:36.328 our response headers is we're -just doing HTP 1.1 200, okay. +just doing HTTP 1.1 200, okay. 338 00:16:36.328 --> 00:16:39.291 @@ -1571,7 +1571,7 @@ response header whatsoever, and 339 00:16:39.291 --> 00:16:43.067 the browser uses those headers like -content types specifically to figure out +content type specifically to figure out 340 00:16:43.067 --> 00:16:44.764 @@ -1585,7 +1585,7 @@ I say, hey, this is a CSS file, 342 00:16:48.184 --> 00:16:51.785 it's not gonna just be like, well that -is a dot CSS, I bet it's a CSS file. +ends in .CSS, I bet it's a CSS file. 343 00:16:51.785 --> 00:16:55.215 diff --git a/en-US/2025-06-09-c-fundamentals/21-bit-shifts.txt b/en-US/2025-06-09-c-fundamentals/21-bit-shifts.txt index 2b1973e7..afa7bf0b 100644 --- a/en-US/2025-06-09-c-fundamentals/21-bit-shifts.txt +++ b/en-US/2025-06-09-c-fundamentals/21-bit-shifts.txt @@ -1,5 +1,5 @@ [00:00:00] ->> Richard Feldman: So we've handled this case where we GET /blog or /blog/ with a slash after it. And now we're gonna need to do a little bit more work to start handling automatic file extensions. So this being a static http server, we need to actually figure out based on the incoming requests file extension, whether or not we should send a particular content type or another. +>> Richard Feldman: So we've handled this case where we GET /blog or /blog/ with a slash after it. And now we're gonna need to do a little bit more work to start handling automatic file extensions. So this being a static http server, we need to actually figure out based on the incoming request's file extension, whether or not we should send a particular content type or another. [00:00:20] So for example, for a PNG, if we're getting a GET of a /blog.png, we want to make sure that not only do we open blog.png and send those bytes from the file system over, but we also wanna make sure that we're sending back a content type header that reflects this is a PNG. @@ -35,7 +35,7 @@ And all of the bytes in between and the two null terminators were identical. And Now, this will actually run when we hope it would. We'll also say, great, this is gonna run if whatever extension, again, assuming that we've already parsed it out, is actually the bytes of that string or [LAUGH] the bytes PNG. Then we run this and set our content type to image/png and all is good. [00:03:30] -And then of course we wanna do the same thing for the CSS and text/css. We do that, and then JS, application Javascript and HTML and text statement. We're gonna do a lot of strcmp calls here, which is a little bit unfortunate, because strcmp is running through every single byte in every single one of these, which means that the more file extensions that we support, the more we are walking through every single one of these. +And then of course we wanna do the same thing for the CSS and text/css. We do that, and then JS, application/javascript and HTML, text/html. We're gonna do a lot of strcmp calls here, which is a little bit unfortunate, because strcmp is running through every single byte in every single one of these, which means that the more file extensions that we support, the more we are walking through every single one of these. [00:03:51] So in order to detect if this was HTML, we first had to go compare it to PNG and let that fail, and then compare it to CSS, let that fail. Each time we're marching through as much of this as we need to until they're different. It's kind of rough. @@ -50,7 +50,7 @@ But this is not something I would normally expect for a static web server. I'm d But it is gonna be a lot faster, and the ergonomics are actually gonna be a little bit better in terms of the getting to actually use the switch statement. So here we go. We're gonna do a fancy trick now. [COUGH] Here are some of these file extensions we wanna support, PNG, CSS, JS, and HTML. [00:05:06] -So here are the bites that correspond to HTML. So H is 104, T is 116, M is 109, L is 108. And here are the bits that go into HTML. So if we have an array of these four bytes, this is what the bit pattern looks like side by side. +So here are the bytes that correspond to HTML. So H is 104, T is 116, M is 109, L is 108. And here are the bits that go into HTML. So if we have an array of these four bytes, this is what the bit pattern looks like side by side. [00:05:21] You may recall all the way back in part two, we talked about how we get to decide how we interpret memory. These ones and zeros, they are our ones and zeros. We can look at them however we want. In fact, if we want to, we can look at these four bytes as one gigantic, 32 bit integer, if we want. @@ -158,10 +158,10 @@ And say, okay, we take this t and we bit shift it over by 8 and take the m over If either one of them is one, then the resulting one is one. And so this effectively means that all of those bit shifts that are sort of adding all those zeros at the end sort of become harmless. Essentially, what this does is it causes us to end up with h, t, m and l in exactly the array like pattern that we want. [00:15:40] -So h is gonna be first, and then t is gonna be next, m is gonna be next, then l is gonna be next after that. And then if we call to int on that, it's going to actually, sorry, we could write a function called to int, which we can call, passing these things, which will just do the bit shifts for us. +So h is gonna be first, and then t is gonna be next, m is gonna be next, then l is gonna be next after that. And then if we call to_int on that, it's going to actually, sorry, we could write a function called to_int, which we can call, passing these things, which will just do the bit shifts for us. [00:15:54] -And then what this will basically do is this will turn these things into an actual integer like we want. So then ideally we would like to be able to say, instead of const int png equals this horrendous, hard coded number, we'd like to be able to call to int and just say, look png/0 HTML, yada yada. +And then what this will basically do is this will turn these things into an actual integer like we want. So then ideally we would like to be able to say, instead of const int png equals this horrendous, hard coded number, we'd like to be able to call to_int and just say, look png/0 HTML, yada yada. [00:16:13] This is much more readable than this, I think we can all agree. It's not quite as readable as a string literal, but I can clearly see, okay, this one's the PNG one, this one's the HTML one. It's a lot harder to make a mistake, or to detect that I've made a mistake than I have if I have these weird, hard-coded numbers here. diff --git a/en-US/2025-06-09-c-fundamentals/21-bit-shifts.vtt b/en-US/2025-06-09-c-fundamentals/21-bit-shifts.vtt index 7c815373..d5415a01 100644 --- a/en-US/2025-06-09-c-fundamentals/21-bit-shifts.vtt +++ b/en-US/2025-06-09-c-fundamentals/21-bit-shifts.vtt @@ -21,7 +21,7 @@ So this being a static http server, 5 00:00:11.882 --> 00:00:16.391 we need to actually figure out based on -the incoming requests file extension, +the incoming request's file extension, 6 00:00:16.391 --> 00:00:20.306 @@ -326,8 +326,8 @@ thing for the CSS and text/css. 69 00:03:35.083 --> 00:03:39.333 -We do that, and then JS, application -Javascript and HTML and text statement. +We do that, and then JS, application/javascript +and HTML, text/html. 70 00:03:39.333 --> 00:03:42.775 @@ -468,7 +468,7 @@ PNG, CSS, JS, and HTML. 99 00:05:06.001 --> 00:05:08.941 -So here are the bites +So here are the bytes that correspond to HTML. 100 @@ -1457,12 +1457,12 @@ then l is gonna be next after that. 308 00:15:46.559 --> 00:15:49.413 -And then if we call to int on that, +And then if we call to_int on that, it's going to actually, sorry, 309 00:15:49.413 --> 00:15:52.921 -we could write a function called to int, +we could write a function called to_int, which we can call, passing these things, 310 @@ -1490,7 +1490,7 @@ this horrendous, hard coded number, 315 00:16:08.246 --> 00:16:13.146 -we'd like to be able to call to int and +we'd like to be able to call to_int and just say, look png/0 HTML, yada yada. 316 diff --git a/en-US/2025-06-09-c-fundamentals/22-preprocessor-macros.txt b/en-US/2025-06-09-c-fundamentals/22-preprocessor-macros.txt index bcbd75d9..d0e8ad5d 100644 --- a/en-US/2025-06-09-c-fundamentals/22-preprocessor-macros.txt +++ b/en-US/2025-06-09-c-fundamentals/22-preprocessor-macros.txt @@ -1,14 +1,14 @@ [00:00:00] ->> Richard Feldman: Unfortunately, this doesn't quite work. So if you have a thing marked as a const in C, first of all, depending on the C compiler, some of them will or will not let you use these in a switch. But even assuming that you're using one of the C compilers, it does allow you to use a constant in a switch. +>> Richard Feldman: Unfortunately, this doesn't quite work. So if you have a thing marked as a const in C, first of all, depending on the C compiler, some of them will or will not let you use these in a switch. But even assuming that you're using one of the C compilers that does allow you to use a constant in a switch. [00:00:18] -This still won't work, because unfortunately, one of the rules of const is that if you're using it at like the top level of the program, you're actually just not allowed to call arbitrary functions like toint at that time, you just can't do it. One of Zig's banner features is called comptime, comptime and Zig does a whole bunch of different things, and it's short for compile time. +This still won't work, because unfortunately, one of the rules of const is that if you're using it at like the top level of the program, you're actually just not allowed to call arbitrary functions like to_int at that time, you just can't do it. One of Zig's banner features is called comptime, comptime and Zig does a whole bunch of different things, and it's short for compile time. [00:00:36] -One of the cool things that it does is that it allows you to basically just run zig functions at compile time like this. So in zig, this would actually just work fine, but in C, unfortunately, it does not. So basically what we want is we wanna make a constant at compile time. +One of the cool things that it does is that it allows you to basically just run Zig functions at compile time like this. So in Zig, this would actually just work fine, but in C, unfortunately, it does not. So basically what we want is we wanna make a constant at compile time. [00:00:52] -So, one of the ways that we can work around this is by converting it from a constant to something else. So here is an example of our code from the previous section. We said like listening on local host port, whatever. We didn't actually do this in the example, but a really obvious thing that you might wanna do is to make a concept for the port so that you can just change it in one place instead of having to go and make sure that the string that we're printing out is, you know, coordinated with that thing. +So, one of the ways that we can work around this is by converting it from a const int to something else. So here is an example of our code from the previous section. We said like listening on localhost port, whatever. We didn't actually do this in the example, but a really obvious thing that you might wanna do is to make a constant for the port so that you can just change it in one place instead of having to go and make sure that the string that we're printing out is, you know, coordinated with that thing. [00:01:16] We'd have to change it in two places, that would be annoying, let's just define it as a constant. Another thing you can do is you can use pound define. Now so far, we've only seen one instruction that starts with a pound, which is pound include, which we've been using for imports, importing libraries and stuff. @@ -17,7 +17,7 @@ We'd have to change it in two places, that would be annoying, let's just define Everything that starts with a pound is a preprocessor directive. And what that means is essentially that, C actually has these two distinct phases to the compiler. First, there's the preprocessor, which basically runs before the actual compiler proper. And the preprocessor's job is to essentially to just sort of copy and paste a bunch of strings together, different parts of your file. [00:01:51] -It has very, very minimal logic that you can actually run, we'll see a tiny, tiny bit of that later, but it's not like a full programming language. Whereas zig, one of the design things of zig was to get rid of the concept of preprocessor directives and instead just be like, yeah, just just write more Zig code. +It has very, very minimal logic that you can actually run, we'll see a tiny, tiny bit of that later, but it's not like a full programming language. Whereas Zig, one of the design things of Zig was to get rid of the concept of preprocessor directives and instead just be like, yeah, just just write more Zig code. [00:02:06] Just write the language, and then you can just mark it as like, this is running at compile time versus at runtime. But C didn't have that, so C is basically, okay, one of the things you can do is you can say, pound, define port and 8080. Now what does this mean? @@ -29,13 +29,13 @@ Well, very similarly to how pound include meant take this library and just copy So literally this code right here it is as if, instead of P-O-R-T, I had written 8080 that's what this does. So this is not a type checked constant that's gonna give me an error if I mess up, no, no, no, no, none of that. It's just like, yeah, this is exactly the same thing as if I had written 8080 right here, instead of P-O-R-T, that is what pound defined does. [00:02:58] -Now you can also take this a step further and write functions with Conde fine. So the way these functions work is essentially you say, here's the name of the function. In this case, I've called it four char because it takes four chars and then does the exact bit wide, bit shifting and bitwise, or trick that we were doing with HTML earlier. +Now you can also take this a step further and write functions with pound define. So the way these functions work is essentially you say, here's the name of the function. In this case, I've called it FOURCHAR because it takes four chars and then does the exact bit wide, bit shifting and bitwise, or trick that we were doing with HTML earlier. [00:03:16] -The backslash, by the way, is just C's way of saying, I want the thing that I'm defining here to go on a different line, you have to be kind of careful with new lines and stuff in these pound defines because they don't have curly braces delivering them functions do. +The backslash, by the way, is just C's way of saying, I want the thing that I'm defining here to go on a different line, you have to be kind of careful with new lines and stuff in these pound defines because they don't have curly braces delimiting them like functions do. [00:03:30] -So this backslash is basically a way of saying, yeah, just pretend this was on the previous line [COUGH] and essentially what this will do is, much how P-O-R-T gets substituted in. This is basically saying, everywhere you call this preprocessor macro, that's what this is called, this is a preprocessor macro. +So this backslash is basically a way of saying, yeah, just pretend this was on the previous line [COUGH] and essentially what this will do is, much how P-O-R-T gets substituted in here. This is basically saying, everywhere you call this preprocessor macro, that's what this is called, this is a preprocessor macro. [00:03:48] Passing whatever arguments you want for these things, it's gonna be exactly as if you had each of those arguments in these different positions, followed by whatever is surrounding them. So it's just a little bit more of an advanced substitution, but again, this is all just happening before the compiler even starts. @@ -44,10 +44,10 @@ Passing whatever arguments you want for these things, it's gonna be exactly as i So when the compiler sees your code, it is as if you had not even written these in the first place. It's just yeah, these things are just like already copy pasted in at every single place that you use these. So [COUGH] at this point we can now say, okay, cool. [00:04:19] -Constant HTML equals a four char, and now we actually are working around that limitation of not being able to do this at compile time. And as a bonus, if you are in one of those situations where you're using a compiler that does not support constant for this, on some Linux distributions that I tried, it didn't support it out the box. +Const int HTML equals a FOURCHAR of this, this, this and this and now we actually are working around that limitation of not being able to do this at compile time. And as a bonus, if you are in one of those situations where you're using a compiler that does not support const int for this, on some Linux distributions that I tried, it didn't support it out the box. [00:04:43] -Some did, some didn't, but anyway, if you're using one of the ones that doesn't, then instead of this constant, you can just do another pound to find right here. And then you've worked around that too because you're basically defining this thing to be equal to this pre-processor macro. +Some did, some didn't, but anyway, if you're using one of the ones that doesn't, then instead of this constant, you can just do another pound define right here. And then you've worked around that too because you're basically defining this thing to be equal to this pre-processor macro. [00:04:56] So at the end of the day, you're ending up with this entire thing being substituted every single time you reference HTML, CSS, or JS. Now that might be kind of conceptually clunky, but from a code readability perspective, again, if we are doing this very silly hack that is not really strictly necessary and maybe more of a performance optimization that is reasonable for a thing on a workshop, but also maybe kinda nice excuse to learn about bit shifts and preprocessor macros. @@ -56,19 +56,19 @@ So at the end of the day, you're ending up with this entire thing being substitu But if you're doing this type of thing, this is actually quite a reasonable way to do it. It does give you, at least when I'm looking at this code right here, HTML convert this thing to the integer thing. I can see that it's the right letters are here, it's a lot easier to debug than back when we were dealing with these weird hard coded numbers. [00:05:36] -And this still lets me use these things in a switch statement. Cool, and yeah, so this will result in exactly the bits in memory that we want, and then we get to do all the nice comparisons, okay. So this is going to be not only nicer to read, but also quite fast, because, again, compared to the stir comp way, which, honestly, if I were just writing this for personal use, I would probably go with the stir comp way. +And this still lets me use these things in a switch statement. Cool, and yeah, so this will result in exactly the bits in memory that we want, and then we get to do all the nice comparisons, okay. So this is going to be not only nicer to read, but also quite fast, because, again, compared to the strcmp way, which, honestly, if I were just writing this for personal use, I would probably go with the strcmp way. [00:05:58] -I wouldn't bother to do this, but in addition to allowing me to use an actual switch statement on this, it is gonna run very fast because we aren't having to go through in March one, bite at a time through each of these, okay? Worst noting though that if you are using a programming language that's not c, almost certainly this is what is actually the equivalent of what your language Just doing. +I wouldn't bother to do this, but in addition to allowing me to use an actual switch statement on this, it is gonna run very fast because we aren't having to go through in and march one byte at a time through each of these, okay? Worth noting though that if you are using a programming language that's not C, almost certainly this is what is actually the equivalent of what your language is doing. [00:06:22] -If you have a language that supports saying extension double equals png, this is almost certainly what that's compiling to. It's compiling to the much less performant and much less, I don't know, nicer for the CPU representation, it's doing much, much more operations. And at the end of the day, the fundamental reason that we're able to get better performance in sea here is that we are doing some pretty heinous memory tricks. +If you have a language that supports saying extension double equals png, this is almost certainly what that's compiling to. It's compiling to the much less performant and much less, I don't know, nicer for the CPU representation, it's doing much, much more operations. And at the end of the day, the fundamental reason that we're able to get better performance in C here is that we are doing some pretty heinous memory tricks. [00:06:50] We're reinterpreting these bytes, we're adding these extra zero bytes if necessary to the extension over here we're doing these pre-processor macros. All this stuff, we're reinterpreting the ones and zeros to be integers at runtime. Only if they happen to be four bytes or less, we're relying on the domain knowledge that in the particular case of a static HTTP server, everything that we need happens to be under four bytes. [00:07:12] -And thankfully.woff happens to be application octet stream, which is the default we want anyway, all of these things, you can look at that, and you can say, this is a giant pile of hacks. This is all very brittle, why don't you just use stir, comp, a normal programmer, which is all very fair. +And thankfully .woff happens to be application octet stream, which is the default we want anyway, all of these things, you can look at that, and you can say, this is a giant pile of hacks. This is all very brittle, why don't you just use strcmp like a normal programmer, which is all very fair. [00:07:24] But the point is, with C, this is there if you need it, if you're trying to write something like postgres or an operating system, and you really, really need that absolute last tiny drop of performance. Because something like this is in a really hot loop, and it's the stakes are a lot higher than a silly little static HTTP server. @@ -77,7 +77,7 @@ But the point is, with C, this is there if you need it, if you're trying to writ This is one of the reasons that C has the absolute highest performance ceiling you can do tricks like this if you need to, not saying you need to all the time, but if you really, really need to, and you want to just be the fastest thing you possibly can be. [00:07:54] -These type of tricks are things that C lets you do, and this is where the trade-off of all of the downsides we've seen, and we've seen plenty of downsides of C's memory unsafety and all the stuff that it lets you do. At the end of the day, if you're trying to think back to some of these original games that ran on PCs and the 90s that were doing things with graphics that people thought was just totally wild, quake and stuff doom, they were doing a lot of these kinds of tricks, and in some cases, even going further to do. +These type of tricks are things that C lets you do, and this is where the trade-off of all of the downsides we've seen, and we've seen plenty of downsides of C's memory unsafety and all the stuff that it lets you do. At the end of the day, if you're trying to think back to some of these original games that ran on PCs in like the 90s that were doing things with graphics that people thought was just totally wild, quake and stuff doom, they were doing a lot of these kinds of tricks, and in some cases, even going further to do. [00:08:21] Do assembly language tricks just to squeeze every last drop of performance they could out of the processors. And the results they got were really amazing. If you want to do the most hardcore performance optimization stuff you can possibly imagine, there's this whole world of this kind of stuff that exists in C that most high level languages just never even get into because it's wildly unsafe [LAUGH] and that is the downside that comes with it. diff --git a/en-US/2025-06-09-c-fundamentals/22-preprocessor-macros.vtt b/en-US/2025-06-09-c-fundamentals/22-preprocessor-macros.vtt index ef13f81c..c5dfdd0d 100644 --- a/en-US/2025-06-09-c-fundamentals/22-preprocessor-macros.vtt +++ b/en-US/2025-06-09-c-fundamentals/22-preprocessor-macros.vtt @@ -17,11 +17,11 @@ will not let you use these in a switch. 4 00:00:12.585 --> 00:00:15.886 But even assuming that you're -using one of the C compilers, +using one of the C compilers 5 00:00:15.886 --> 00:00:18.423 -it does allow you to use +that does allow you to use a constant in a switch. 6 @@ -37,7 +37,7 @@ level of the program, you're actually 8 00:00:26.153 --> 00:00:29.636 just not allowed to call arbitrary -functions like toint at that time, +functions like to_int at that time, 9 00:00:29.636 --> 00:00:30.778 @@ -60,11 +60,11 @@ that it allows you to basically just run 13 00:00:40.474 --> 00:00:42.609 -zig functions at compile time like this. +Zig functions at compile time like this. 14 00:00:42.609 --> 00:00:47.082 -So in zig, this would actually just +So in Zig, this would actually just work fine, but in C, unfortunately, 15 @@ -83,7 +83,7 @@ around this is by converting it from 18 00:00:56.403 --> 00:00:58.127 -a constant to something else. +a const int to something else. 19 00:00:58.127 --> 00:01:01.746 @@ -92,7 +92,7 @@ code from the previous section. 20 00:01:01.746 --> 00:01:04.935 -We said like listening on local host port, +We said like listening on localhost port, whatever. 21 @@ -103,7 +103,7 @@ but a really obvious thing that 22 00:01:08.085 --> 00:01:10.235 you might wanna do is to make -a concept for the port so +a constant for the port so 23 00:01:10.235 --> 00:01:13.535 @@ -188,8 +188,8 @@ it's not like a full programming language. 40 00:01:58.580 --> 00:02:02.266 -Whereas zig, one of the design things -of zig was to get rid of the concept of +Whereas Zig, one of the design things +of Zig was to get rid of the concept of 41 00:02:02.266 --> 00:02:05.243 @@ -284,7 +284,7 @@ that is what pound defined does. 60 00:02:58.142 --> 00:03:02.270 Now you can also take this a step further -and write functions with Conde fine. +and write functions with pound define. 61 00:03:02.270 --> 00:03:05.200 @@ -297,8 +297,8 @@ here's the name of the function. 63 00:03:07.018 --> 00:03:10.928 -In this case, I've called it four -char because it takes four chars and +In this case, I've called it +FOURCHAR because it takes four chars and 64 00:03:10.928 --> 00:03:14.242 @@ -328,7 +328,7 @@ new lines and stuff in these pound 69 00:03:26.128 --> 00:03:30.088 defines because they don't have curly -braces delivering them functions do. +braces delimiting them like functions do. 70 00:03:30.088 --> 00:03:33.381 @@ -343,7 +343,7 @@ the previous line [COUGH] and 72 00:03:36.459 --> 00:03:41.128 essentially what this will do is, -much how P-O-R-T gets substituted in. +much how P-O-R-T gets substituted in here. 73 00:03:41.128 --> 00:03:45.393 @@ -406,8 +406,8 @@ okay, cool. 85 00:04:19.607 --> 00:04:23.969 -Constant HTML equals a four char, -and now we actually are working +Const int HTML equals a FOURCHAR of this, this, +this and this, and now we actually are working 86 00:04:23.969 --> 00:04:28.503 @@ -422,7 +422,7 @@ of those situations where you're 88 00:04:33.343 --> 00:04:37.655 using a compiler that does not -support constant for this, +support const int for this, 89 00:04:37.655 --> 00:04:43.382 @@ -437,7 +437,7 @@ you're using one of the ones that doesn't, 91 00:04:46.335 --> 00:04:49.099 then instead of this constant, you can -just do another pound to find right here. +just do another pound define right here. 92 00:04:49.099 --> 00:04:53.451 @@ -535,13 +535,13 @@ read, but also quite fast, because, again, 111 00:05:52.064 --> 00:05:55.565 -compared to the stir comp way, which, +compared to the strcmp way, which, honestly, if I were just writing this for 112 00:05:55.565 --> 00:05:58.107 personal use, I would probably -go with the stir comp way. +go with the strcmp way. 113 00:05:58.107 --> 00:06:03.257 @@ -555,13 +555,13 @@ run very fast because we aren't having 115 00:06:08.487 --> 00:06:13.330 -to go through in March one, bite at +to go through in and march one byte at a time through each of these, okay? 116 00:06:13.330 --> 00:06:17.502 -Worst noting though that if you are using -a programming language that's not c, +Worth noting though that if you are using +a programming language that's not C, 117 00:06:17.502 --> 00:06:21.611 @@ -570,7 +570,7 @@ the equivalent of what your language 118 00:06:21.611 --> 00:06:22.311 -Just doing. +is doing. 119 00:06:22.311 --> 00:06:27.444 @@ -599,7 +599,7 @@ reason that we're able to get better 124 00:06:46.012 --> 00:06:50.209 -performance in sea here is that we are +performance in C here is that we are doing some pretty heinous memory tricks. 125 @@ -634,7 +634,7 @@ we need happens to be under four bytes. 131 00:07:12.766 --> 00:07:15.503 -And thankfully.woff happens to +And thankfully .woff happens to be application octet stream, 132 @@ -650,7 +650,7 @@ this is a giant pile of hacks. 134 00:07:20.892 --> 00:07:24.061 This is all very brittle, why don't you -just use stir, comp, a normal programmer, +just use strcmp like a normal programmer, 135 00:07:24.061 --> 00:07:24.951 @@ -722,7 +722,7 @@ think back to some of these original games 149 00:08:09.124 --> 00:08:13.417 -that ran on PCs and the 90s that were +that ran on PCs in like the 90s that were doing things with graphics that people 150 diff --git a/en-US/2025-06-09-c-fundamentals/23-platform-specific-macros.txt b/en-US/2025-06-09-c-fundamentals/23-platform-specific-macros.txt index 601c2496..875b5565 100644 --- a/en-US/2025-06-09-c-fundamentals/23-platform-specific-macros.txt +++ b/en-US/2025-06-09-c-fundamentals/23-platform-specific-macros.txt @@ -14,7 +14,7 @@ We are just read the request in. We're gonna go read the from a file descriptor And unfortunately, we have this like, sort of annoying thing, of like, first we have to, like, read them into our buffer. And not only is that annoying, because it means we have to, like, do this extra step, of like, reading it in, and we got to figure out the size of the buffer and all that. [00:01:19] -That's kind of annoying, but also separately, and like, in dealing with the memory implications of that, and like, considering we want to use malloc are going to use chunked reads and yada yada. But also it's just less efficient in general, if you're able to sort of let the operating system hang out and, like, do its own thing, rather than, like, jumping back and forth between OS functions and what's called user space functions, where, like. +That's kind of annoying, but also separately, and like, in dealing with the memory implications of that, and like, considering whether we want to use malloc, are we going to use chunked reads and yada yada. But also it's just less efficient in general, if you're able to sort of let the operating system hang out and, like, do its own thing, rather than, like, jumping back and forth between OS functions and what's called user space functions, where, like. [00:01:39] The functions in our program, it's better to let the operating system do more stuff. So sendfile is this very convenient function that essentially lets us say, I'm gonna give you two file descriptors and a number of bytes. I'm just like, hey, just take this many bytes from that one and send them over there, which is exactly what we want to do here. @@ -26,22 +26,22 @@ And that allows us to cut out that intermediary of the reading it into the buffe Also, they're probably doing a lot of other [LAUGH] general overhead kind of stuff, but this one, if I had to guess would? I would guess that this one's maybe the most significant thing to avoid this, like handoff work. So basically, source file takes a source file descriptor, a destination file descriptor, and then a number of bytes, and it just says, cool operating system, you're gonna take this many bytes from the source file descriptor, namely. [00:02:35] -In this case, our file that we've opened, and then send them right over to the socket for the file descriptor as a destination. Okay, now here's where things get a little bit tricky. So here is the type of sendfile. So it's like, you have the out file descriptor, so that's the one that we're writing to in file descriptor, one that we're reading from. +In this case, our file that we've opened, and then send them right over to the socket file descriptor as a destination. Okay, now here's where things get a little bit tricky. So here is the type of sendfile. So it's like, you have the out file descriptor, so that's the one that we're writing to in file descriptor, one that we're reading from. [00:02:52] This is sort of optional offset. If you want to say, like, I don't want to read from like, the very start of this file descriptor, maybe I want to, like, start, 500 bytes in for some reason, and then finally the count of the bytes. Here is another way you can have a sendfile work. [00:03:07] -This one returns an int instead of a size_t. It takes a file descriptor instead of a second file descriptor. It takes an int called s, and we'll talk about that in a sec. It does take the offset, but it's over here, and it takes like a length instead of like. +This one returns an int instead of a ssize_t. It takes a file descriptor instead of a second file descriptor. It takes an int called s, and we'll talk about that in a sec. It does take the offset, but it's over here, and it takes like a length instead of like. [00:03:19] -Being a size t, it's an off t address. And then we have this sf-hdtr, which is a sure, and then we have some flags, so like, what's the deal with this? Why are we talking about this thing? Unfortunately, this is what send file is on Linux, and this is what it is on Mac. +Being a size_t, it's an off_t address. And then we have this sf_hdtr, which is a hdtr, and then we have some flags, so like, what's the deal with this? Why are we talking about this thing? Unfortunately, this is what send file is on Linux, and this is what it is on Mac. [00:03:39] They have the same name and they do the same job, but they have totally different types, totally different APIs. Now, fortunately, we have been so far pretty insulated from this. But here we have encountered our first example, and there are other ones in there where, although, yes, C at a language level is going to compile to the same stuff. [00:03:56] -The libraries are not always identical when you go to different operating systems or different operating system flavors. So here's the Linux manual page for sendfile. You notice that like the pound include here is sys/stenfile.h. This doesn't even exist on Mac OS. And we see that this has the, I would say, nicer of the two APIs for sure, type that we saw earlier. +The libraries are not always identical when you go to different operating systems or different operating system flavors. So here's the Linux manual page for sendfile. You notice that like the pound include here is sys/sendfile.h. This doesn't even exist on Mac OS. And we see that this has the, I would say, nicer of the two APIs for sure, type that we saw earlier. [00:04:19] This is the manual page for that on Linux. And then here we have, this is the actually the BSD version, because Mac OS is built on top of BSD, which is a different flavor of Unix from Linux there. So, like different parts of the Unix tree, Linux and BSD. @@ -50,7 +50,7 @@ This is the manual page for that on Linux. And then here we have, this is the ac And here we have three includes [LAUGH] to get their sendfile, none of which are sendfile.h. [COUGH] and basically, at the end of the day, you look at these and you think, like, hey, what happened to portable assembly? Well, you may recall back when I introduced that term, I did mention there's a little bit of a caveat that oftentimes, and so far up to this point, we have been able to dodge this. [00:04:53] -Like, none of the APIs that we've been using have happened to have been different on different operating systems, but they can be. And this is a case where they target totally are. [COUGH] so the next question is, okay, well, wait a minute, so I get it that these are two different things. +Like, none of the APIs that we've been using have happened to have been different on different operating systems, but they can be. And this is a case where they totally are. [COUGH] so the next question is, okay, well, wait a minute, so I get it that these are two different things. [00:05:07] Does this mean I have to have two separate code bases now, like just because I want to use sendfile, because it's obviously the best tool for the job of what we want to use. And now I need to, like, fork my code base and have one that's for Linux and one that's for Mac OS, and they're totally identical. @@ -59,7 +59,7 @@ Does this mean I have to have two separate code bases now, like just because I w Except for this one part. Fortunately, no we can do something better than this using target-specific preprocessor macros. So I mentioned that earlier that on the Linux version only, we need to include a sys/sendfile.h. Here's how we can do that. Basically, one of the other preprocessor directors we can have is ifdef. [00:05:37] -And what this means is basically if, at some point. And anybody who we have imported has done a pound define of __linux__. And we don't even care what it was defined as we're just like, did anyone define that in any was there a pound define at a point, at any point of this? +And what this means is basically if, at some point. And anybody who we have imported has done a pound define of __linux__. And we don't even care what it was defined as we're just like, did anyone define that in any... Was there a pound define at some point, at any point of this? [00:05:55] If so, then I want to just process this preprocessor directive immediately, which is just gonna copy paste all of that in there. And then here is the pound end, if that goes with the ifdef. Essentially, what this is doing is saying, yeah, I'm going to trust that the C compiler knows. @@ -68,34 +68,34 @@ If so, then I want to just process this preprocessor directive immediately, whic Are we building for Linux or building this binary for Mac OS? And it's going to define, like the pound define at the very beginning for me, __linux. If it's Linux, then we'll see the Apple one in a sec. And therefore I can now write in the middle of my C code, just like, hey, if we're building for Linux, there's just different source code here, magically. [00:06:31] -And if we're building for Mac OS, there's other different source code here. So to go through the the actual like, sendfile version of this. Like down below after we've done the include there. Basically, we say elif Linux, we have Selenix specific code, and then elif, which is the pre-processor directive for else if, you can already kind of see why Zig was like. +And if we're building for Mac OS, there's other different source code here. So to go through the the actual like, sendfile version of this. Like down below after we've done the include there. Basically, we say #ifdef Linux, we have Linux specific code, and then elif, which is the pre-processor directive for else if, you can already kind of see why Zig was like. [00:06:52] -We're just gonna let you run the language at compile time. We're not gonna have if,def, and elif, and endif, and define. And it's like no, we'll just, you just do the language at comp time is fine. And also, for some reason, Linux is like lowercase, but then Apple is uppercase. +We're just gonna let you run the language at compile time. We're not gonna have ifdef, and elif, and endif, and define. And it's like no, we'll just, you just do the language at comp time is fine. And also, for some reason, Linux is like lowercase, but then Apple is uppercase. [00:07:04] I'm not exactly sure what's going on there. And then finally, we have an else. And then basically, you can also have a pound error, [LAUGH] which is basically, well, what happens if neither of these are defined? Well, I would rather just get a build time error saying like, hey, you're trying to build for something that doesn't have sendfile, and like we kind of rely on that, so error out. [00:07:23] -Or of course, this could be, if we didn't want to do this error, we could just say like, well, this is the part where rather than using send file at all. We're just going to fall back on the thing that we've already used where we like read it into a buffer and then like write it from the buffer out. +Or of course, this could be, if we didn't want to do this error, we could just say like, well, this is the part where rather than using sendfile at all. We're just going to fall back on the thing that we've already used where we like read it into a buffer and then like write it from the buffer out. [00:07:34] -So be a little less efficient, but at least it'll still work if we're targeting something other than Linux or OS, such as windows. Also worth noting that I mentioned at the very beginning of this course that we're not doing Windows-specific APIs here, in large part because, they have all these differences. +So be a little less efficient, but at least it'll still work if we're targeting something other than Linux or Mac OS, such as Windows. Also worth noting that I mentioned at the very beginning of this course that we're not doing Windows-specific APIs here, in large part because, they have all these differences. [00:07:51] So if you can imagine this difference in sendfile, this would have also existed for basically everything else we've seen here. So like open, write, read, all of those have different names and different APIs and Windows, but the structure of the code would be about the same if we wanted to support Windows. [00:08:07] -Basically, what we would have is just a whole bunch more of these. So we would have like, we're gonna do a read, okay, if def windows do it the windows way. Otherwise do it, this way. If we wanna do it open, okay, ifdef windows do it this way, otherwise, that. +Basically, what we would have is just a whole bunch more of these. So we would have like, we're gonna do a read, okay, #ifdef Windows do it the Windows way. Otherwise do it, this way. If we wanna do an open, okay, #ifdef Windows do it this way, otherwise, that. [00:08:20] -You can imagine that would've made the course really kind of clunky to go through if we did that. But it's actually not that wild in terms of like how much of an effect it would have on your program other than sort of littering these if-ifs everywhere. This of course could lead you to say, what I'm gonna do? +You can imagine that would've made the course really kind of clunky to go through if we did that. But it's actually not that wild in terms of like how much of an effect it would have on your program other than sort of littering these ifdefs everywhere. This of course could lead you to say, what I'm gonna do? [00:08:33] I'm just gonna like make a generic version of open that works on Linux and Mac OS, and Windows, and just like write my functions so I can sort of isolate these preprocessor macros over there. And then at that point, you might say, maybe I'll make a cross-platform standard library and make a library that people can just import. [00:08:49] -So they don't have to do that themselves, etc. So this is where you get sort of like people who want to use more than just the C standard library, making things cross-platform is a common reason to want to read for something like that. Okay, so as we're gonna do in the exercise, this is the part where we're like, cool, I'm gonna call sendfile, passing like Linux specific arguments or macOS-specific arguments. +So they don't have to do that themselves, etc. So this is where you get sort of like people who want to use more than just the C standard library, making things cross-platform is a common reason to want to reach for something like that. Okay, so as we're gonna do in the exercise, this is the part where we're like, cool, I'm gonna call sendfile, passing like Linux specific arguments or macOS-specific arguments. [00:09:12] And then we can just have things just work. So to summarize everything we talked about, we started off talking about bit shifts and switches. Basically using the combination of those, plus this other kind of wild hack that we're doing to convert things into integers that are clearly strings. @@ -104,5 +104,5 @@ And then we can just have things just work. So to summarize everything we talked We talked about preprocessor macros as a way to improve the ergonomics of that. So that rather than having to, like, write out this hard-coded like, billion plus number, we could actually just write some code that at least has the contents of the string that we care about. And yet be able to use it in a switch and all that. [00:09:44] -And then finally, we talked about how to access platform specific code, because with send file. We actually need to be able to do something completely different when it comes to Linux versus Mac OS, just because the APIs are so different. +And then finally, we talked about how to access platform specific code, because with sendfile. We actually need to be able to do something completely different when it comes to Linux versus Mac OS, just because the APIs are so different. diff --git a/en-US/2025-06-09-c-fundamentals/23-platform-specific-macros.vtt b/en-US/2025-06-09-c-fundamentals/23-platform-specific-macros.vtt index e4d40413..0313a117 100644 --- a/en-US/2025-06-09-c-fundamentals/23-platform-specific-macros.vtt +++ b/en-US/2025-06-09-c-fundamentals/23-platform-specific-macros.vtt @@ -142,8 +142,8 @@ implications of that, and like, 30 00:01:23.853 --> 00:01:26.845 -considering we want to use malloc are -going to use chunked reads and yada yada. +considering whether we want to use malloc, are +we going to use chunked reads and yada yada. 31 00:01:26.845 --> 00:01:29.086 @@ -261,7 +261,7 @@ our file that we've opened, and 54 00:02:37.486 --> 00:02:41.604 then send them right over to the socket -for the file descriptor as a destination. +file descriptor as a destination. 55 00:02:41.604 --> 00:02:45.597 @@ -309,7 +309,7 @@ can have a sendfile work. 64 00:03:07.555 --> 00:03:10.138 This one returns an int -instead of a size_t. +instead of a ssize_t. 65 00:03:10.138 --> 00:03:12.849 @@ -332,12 +332,12 @@ it takes like a length instead of like. 69 00:03:19.925 --> 00:03:22.894 -Being a size t, it's an off t address. +Being a size_t, it's an off_t address. 70 00:03:22.894 --> 00:03:26.773 -And then we have this sf-hdtr, -which is a sure, and +And then we have this sf_hdtr, +which is a hdtr, and 71 00:03:26.773 --> 00:03:31.456 @@ -400,7 +400,7 @@ sendfile. 83 00:04:06.806 --> 00:04:10.277 You notice that like the pound -include here is sys/stenfile.h. +include here is sys/sendfile.h. 84 00:04:10.277 --> 00:04:12.911 @@ -481,7 +481,7 @@ but they can be. 100 00:04:59.100 --> 00:05:01.166 And this is a case where -they target totally are. +they totally are. 101 00:05:01.166 --> 00:05:03.946 @@ -565,8 +565,8 @@ as we're just like, did anyone define that 118 00:05:52.177 --> 00:05:55.306 -in any was there a pound define -at a point, at any point of this? +in any... Was there a pound define +at some point, at any point of this? 119 00:05:55.306 --> 00:05:59.014 @@ -639,8 +639,8 @@ done the include there. 133 00:06:42.509 --> 00:06:46.868 -Basically, we say elif Linux, we have -Selenix specific code, and then elif, +Basically, we say #ifdef linux, we have +Linux specific code, and then elif, 134 00:06:46.868 --> 00:06:49.732 @@ -659,7 +659,7 @@ the language at compile time. 137 00:06:54.258 --> 00:06:57.313 -We're not gonna have if,def, and +We're not gonna have ifdef, and elif, and endif, and define. 138 @@ -714,7 +714,7 @@ want to do this error, we could just say 148 00:07:26.570 --> 00:07:29.530 like, well, this is the part where -rather than using send file at all. +rather than using sendfile at all. 149 00:07:29.530 --> 00:07:32.654 @@ -734,7 +734,7 @@ at least it'll still work if we're 152 00:07:38.814 --> 00:07:42.412 targeting something other than Linux or -OS, such as windows. +Mac OS, such as Windows. 153 00:07:42.412 --> 00:07:46.284 @@ -785,7 +785,7 @@ we're gonna do a read, okay, 163 00:08:12.769 --> 00:08:14.938 -if def windows do it the windows way. +#ifdef Windows do it the Windows way. 164 00:08:14.938 --> 00:08:17.085 @@ -793,8 +793,8 @@ Otherwise do it, this way. 165 00:08:17.085 --> 00:08:20.758 -If we wanna do it open, okay, ifdef -windows do it this way, otherwise, that. +If we wanna do an open, okay, #ifdef +Windows do it this way, otherwise, that. 166 00:08:20.758 --> 00:08:24.245 @@ -813,7 +813,7 @@ of like how much of an effect it would 169 00:08:28.420 --> 00:08:32.001 have on your program other than sort -of littering these if-ifs everywhere. +of littering these ifdefs everywhere. 170 00:08:32.001 --> 00:08:33.952 @@ -862,7 +862,7 @@ cross-platform is a common reason to want 179 00:09:00.198 --> 00:09:02.028 -to read for something like that. +to reach for something like that. 180 00:09:02.028 --> 00:09:04.601 @@ -936,7 +936,7 @@ to access platform specific code, 194 00:09:47.232 --> 00:09:48.243 -because with send file. +because with sendfile. 195 00:09:48.243 --> 00:09:53.669 diff --git a/en-US/2025-06-09-c-fundamentals/24-web-server-image-support-exercise.txt b/en-US/2025-06-09-c-fundamentals/24-web-server-image-support-exercise.txt index 3a3c36fc..a4ba5c70 100644 --- a/en-US/2025-06-09-c-fundamentals/24-web-server-image-support-exercise.txt +++ b/en-US/2025-06-09-c-fundamentals/24-web-server-image-support-exercise.txt @@ -1,33 +1,33 @@ [00:00:00] ->> Richard Feldman: All right, let's get to our final exercise, which is for part six. So now you can see we not only have this whole big long list of, includes up top but we also have ifdef Linux here for our sys slash send file. We're gonna build this thing, that was 5 again, and I'm still listening on port 8080, so let's do that. +>> Richard Feldman: All right, let's get to our final exercise, which is for part six. So now you can see we not only have this whole big long list of, includes up top but we also have #ifdef Linux here for our sys/sendfile. We're gonna build this thing, that was 5 again, and I'm still listening on port 8080, so let's do that. [00:00:24] -Great listening on port 8080, so now you can see if I refresh and try to load the front end masters page it doesn't work at all, that's okay, though. That's because we haven't completed the exercise yet. So right now we're seeing a blank page, but when we're done with the exercise, we will actually see something much nicer than a blank page, which is a working front end masters homepage. +Great listening on port 8080, so now you can see if I refresh and try to load the Frontend Masters page it doesn't work at all, that's okay, though. That's because we haven't completed the exercise yet. So right now we're seeing a blank page, but when we're done with the exercise, we will actually see something much nicer than a blank page, which is a working Frontend Masters homepage. [00:00:42] -Okay, so this one, unlike the others, does not have a bunch of different things to jump around and do. If you want to, you can spend some time looking through some of the source code here. I did decide to use the pound define style here instead of constant, just in case you are running one of those Linux distros that doesn't support it. +Okay, so this one, unlike the others, does not have a bunch of different things to jump around and do. If you want to, you can spend some time looking through some of the source code here. I did decide to use the #define style here instead of const int, just in case you are running one of those Linux distros that doesn't support it. [00:00:59] -But if you're on macOS, you could just do constant here. We're doing the, jpeg, css png, jpej, JS, etc. We're doing the fancy switch thing right here. All the stuff that we talked about, and now we are using that to actually send back this content type header. So you may recall this was the last missing piece we had at the end of the previous section where it wasn't recognizing like any of the CSS or anything like that. +But if you're on macOS, you could just do const int here, if you wanted to. We're doing the, jpg, css, png, jpeg, js, etc. We're doing the fancy switch thing right here. All the stuff that we talked about, and now we are using that to actually send back this content type header. So you may recall this was the last missing piece we had at the end of the previous section where it wasn't recognizing like any of the CSS or anything like that. [00:01:25] -The reason that nothing is loading is that the one thing that we are missing here is that I have not actually implemented the call to send file. So this is the only section of the thing that requires any modification. So the entire exercise is basically just go check out the docs for these and try to implement the two different calls to send file. +The reason that nothing is loading is that the one thing that we are missing here is that I have not actually implemented the call to sendfile. So this is the only section of the thing that requires any modification. So the entire exercise is basically just go check out the docs for these and try to implement the two different calls to sendfile. [00:01:45] -Worth noting that something we are doing here is we are actually making these variables of byte sent and send failed locally. Now you got to remember here that these are not actually different scopes. This is not like there's no curly braces around this. These are basically out dented and only one of the other is going to get actually included in here, which is relevant because we end up using it later. +Worth noting that something we are doing here is we are actually making these variables of byte_sent and send_failed locally. Now you got to remember here that these are not actually different scopes. This is not like there's no curly braces around this. These are basically out dented and only one or the other is going to get actually included in here, which is relevant because we end up using it later. [00:02:07] -But they are indented because they're inside the ifdef. So that's what's going on there is like we're defining one or the other here. They do actually have different types, which is kind of funny. But nevertheless, we can still like do subtraction on them because C is loosey goosey with its integer conversions, fortunately for our sake, in this case. +But they are indented because they're inside the #ifdef. So that's what's going on there is like we're defining one or the other here. They do actually have different types, which is kind of funny. But nevertheless, we can still like do subtraction on them because C is loosey goosey with its integer conversions, fortunately for our sake, in this case. [00:02:24] -So basically, just need to go look at the docs for these two things. And I will warn you this, well especially the MacOS 1 is a little bit funky, but just take a few minutes and go through and see if you can get it working. +So basically, just need to go look at the docs for these two things. And I will warn you this, well especially the MacOS one is a little bit funky, but just take a few minutes and go through and see if you can get it working. >> Richard Feldman: So for this one, unlike the others, I'm actually just gonna just walk you through the solution rather than typing out by hand. [00:02:51] Mostly because all the typing out by hand accomplishes is essentially, I go look at the docs, and then look at what we're doing. So essentially, I want to just mainly talk through the differences between these two. So the Linux version, as you see from the docs, if you went and looked those up, we send the two file descriptors first. [00:03:07] -Now, if you look at the MacOS docs, one of the things that's most striking about the difference here is that the Linux one just returns how many bytes were successfully sent. So this is very similar to what we saw with like read will return how many bytes B Bytes were actually read. +Now, if you look at the MacOS docs, one of the things that's most striking about the difference here is that the Linux one just returns how many bytes were successfully sent. So this is very similar to what we saw with like read will return how many bytes were actually read. [00:03:21] Also, if you like try to write, potentially it might not write all the bytes if the thing that it's trying to write to had some sort of limit setup. Same kind of deal here, where basically it's saying, hey, here is you told me that you wanted to send this many bytes, but it's possible that I sent fewer bytes than that. @@ -36,10 +36,10 @@ Also, if you like try to write, potentially it might not write all the bytes if Now this is very important to know, because we actually do want to potentially put these in a loop. So this is actually how we're doing the chunking here. We're basically saying Ok, if you didn't send all the bytes that I told you to send, that's fine. I'm just going to decrement, how many bytes we have remaining to send. [00:03:52] -Go back to the top of the loop and just keep doing it again over and over again until all the bytes finally get successfully sent. Now how do we get this actual byte sent value? This is one of the ways where Linux and macros APIs differ. So in the Linux one, send file just returns it. +Go back to the top of the loop and just keep doing it again over and over again until all the bytes finally get successfully sent. Now how do we get this actual bytes_sent value? This is one of the ways where Linux and MacOS APIs differ. So in the Linux one, sendfile just returns it. [00:04:10] -And then our job to detect whether or not sending failed is the usual check for the return value was -1. If it was sent failed, then Ok, fine, we break. This is a pretty unfortunate scenario where, if this were a production HTTP server, as opposed to just a little local one. +And then our job to detect whether or not sending failed is the usual check for the return value was -1. If it was sent_failed, then Ok, fine, we break. This is a pretty unfortunate scenario where, if this were a production HTTP server, as opposed to just a little local one. [00:04:27] We might wanna try to do some extra work, to try to more gracefully handle these errors. But basically, in this case, because we're doing the send, what's happening here is that if we already sent some number of bytes. Well, the first bytes that we sent at the very beginning of the of the thing that we're sending over the network are 200 okay? @@ -51,25 +51,25 @@ Because as far as we know, by the time we got here, we're all set. We're good, w We can try to gracefully handle this by basically doing something along the lines of Ok, well, we remember that we already do the partial send. So let's actually go and retry it and try to send the rest of the bytes as best we can. Or maybe we try to do something like send some sort of extra content that comes back and just displays a big, no, it was truncated message on the screen. [00:05:28] -And then maybe we also detect, well if we didn't send anything yet, if we were in the first iteration of this loop. Now we can just go ahead and send a 500, so lots of potential ways we could try to make this error handling better. This is not really specific to send file. +And then maybe we also detect, well if we didn't send anything yet, if we were in the first iteration of this loop. Now we can just go ahead and send a 500, so lots of potential ways we could try to make this error handling better. This is not really specific to sendfile. [00:05:39] -This is just in general. If we're writing to the socket, and whether it's via send file or via right and that operation fails after we've already sent some amount of data, we're going to potentially have this problem. But yeah, so we need to know whether sending fail and we also need to know how many bytes were sent and the MacOS API for this or the the BSC one. +This is just in general. If we're writing to the socket, and whether it's via sendfile or via write and that operation fails after we've already sent some amount of data, we're going to potentially have this problem. But yeah, so we need to know whether sending fail and we also need to know how many bytes were sent and the MacOS API for this or the the BSD one. [00:06:00] -Very different, so here we're actually doing basically the number of bytes that were sent is actually equal to stats.st, size, or at least we're assuming that as the starting point. And then we send the address of that, and basically it will use that both for getting what is the actual size? +Very different, so here we're actually doing basically the number of bytes that were sent is actually equal to stats.st_size, or at least we're assuming that as the starting point. And then we send the address of that, and basically it will use that both for getting what is the actual size? [00:06:19] -What is the actual number of bytes that you want to send. And then also, when we call send file, it will, after reading that to see how many bytes we want to send, it will override it with how many bytes it actually sent. Again, funky C APIs. [LAUGH] I look at this and I say, I think the Linux one makes more sense to me. +What is the actual number of bytes that you want to send. And then also, when we call sendfile, it will, after reading that to see how many bytes we want to send, it will override it with how many bytes it actually sent. Again, funky C APIs. [LAUGH] I look at this and I say, I think the Linux one makes more sense to me. [00:06:36] This seems nicer to use, but the BSD authors decided to do it this way, and so if you want to do it on MacOS, this is what you got to use. The other notable difference here is that there's a couple of extra flags here. So this version of sendfile is more configurable than this version. [00:06:52] -Now, this is an example of sometimes operating systems will add new functionality that's not available in other operating systems. A classic example of this that happens today is IOU ring. You may have heard of this. This is something that's available in Linux. It's very nice for certain types of high performance IO operations, especially over the network. +Now, this is an example of sometimes operating systems will add new functionality that's not available in other operating systems. A classic example of this that happens today is io_uring. You may have heard of this. This is something that's available in Linux. It's very nice for certain types of high performance IO operations, especially over the network. [00:07:10] -It's just not available in Mac OS, they don't have a direct equivalent of IOU ring. And so if you're trying to write a cross platform like networking library, that uses IOU ring, what you end up with is. If dev on Linux is huge because IOU ring is very different in terms of how it sets up its abstractions for doing this type of network stuff, then the other ways that other alternatives use it. +It's just not available in Mac OS, they don't have a direct equivalent of io_uring. And so if you're trying to write a cross platform like networking library, that uses io_uring, what you end up with is. #ifdef on Linux is huge because io_uring is very different in terms of how it sets up its abstractions for doing this type of network stuff, then the other ways that other alternatives use it. [00:07:33] And so there it's not just two lines of code, it's a very big difference. And these little differences in arguments that we see here are a much smaller example of that. Where it's I don't really know what these options do, but clearly Mac OS supports some degree of additional configuration that the Linux one does, because it's strictly sending more arguments over. @@ -81,5 +81,5 @@ Okay, so at the end of this, we do that and then we've actually set, I've sent a And the cool part is, I've downloaded this locally, this is basically a copy of the Frontend Masters website that I just downloaded all the HTML and CSS and all the fonts and everything into my local directories. And there it is, beautiful. The entire frontendmasters.com website served locally, blazing fast. [00:08:28] -[LAUGH] See about 300 lines of code that we built from scratch in the course of this workshop using no third party dependencies, just raw, close to the metal operating system stuff. And it all works, look at that. +[LAUGH] C about 300 lines of code that we built from scratch in the course of this workshop using no third party dependencies, just raw, close to the metal operating system stuff. And it all works, look at that. diff --git a/en-US/2025-06-09-c-fundamentals/24-web-server-image-support-exercise.vtt b/en-US/2025-06-09-c-fundamentals/24-web-server-image-support-exercise.vtt index 57898de0..76cbf864 100644 --- a/en-US/2025-06-09-c-fundamentals/24-web-server-image-support-exercise.vtt +++ b/en-US/2025-06-09-c-fundamentals/24-web-server-image-support-exercise.vtt @@ -12,8 +12,8 @@ have this whole big long list of, 3 00:00:10.230 --> 00:00:16.920 -includes up top but we also have ifdef -Linux here for our sys slash send file. +includes up top but we also have #ifdef +Linux here for our sys/sendfile. 4 00:00:16.920 --> 00:00:20.450 @@ -32,7 +32,7 @@ now you can see if I refresh and 7 00:00:27.754 --> 00:00:32.193 -try to load the front end masters page it +try to load the Frontend Masters page it doesn't work at all, that's okay, though. 8 @@ -52,8 +52,8 @@ much nicer than a blank page, 11 00:00:40.294 --> 00:00:42.385 -which is a working front -end masters homepage. +which is a working frontend +Masters homepage. 12 00:00:42.385 --> 00:00:44.857 @@ -75,8 +75,8 @@ through some of the source code here. 16 00:00:53.934 --> 00:00:56.654 -I did decide to use the pound define -style here instead of constant, +I did decide to use the #define +style here instead of const int, 17 00:00:56.654 --> 00:00:59.914 @@ -86,12 +86,12 @@ Linux distros that doesn't support it. 18 00:00:59.914 --> 00:01:04.264 But if you're on macOS, -you could just do constant here. +you could just do const int here, if you wanted to. 19 00:01:04.264 --> 00:01:10.608 -We're doing the, jpeg, -css png, jpej, JS, etc. +We're doing the, jpg, +css, png, jpeg, js, etc. 20 00:01:10.608 --> 00:01:13.343 @@ -129,7 +129,7 @@ the one thing that we are missing here is 27 00:01:29.356 --> 00:01:32.342 that I have not actually -implemented the call to send file. +implemented the call to sendfile. 28 00:01:32.342 --> 00:01:36.371 @@ -144,7 +144,7 @@ just go check out the docs for 30 00:01:40.915 --> 00:01:45.474 these and try to implement the two -different calls to send file. +different calls to sendfile. 31 00:01:45.474 --> 00:01:50.104 @@ -153,8 +153,8 @@ here is we are actually making 32 00:01:50.104 --> 00:01:53.723 -these variables of byte sent and -send failed locally. +these variables of byte_sent and +send_failed locally. 33 00:01:53.723 --> 00:01:56.587 @@ -169,7 +169,7 @@ curly braces around this. 35 00:02:00.295 --> 00:02:03.510 These are basically out dented and -only one of the other is going to get +only one or the other is going to get 36 00:02:03.510 --> 00:02:07.244 @@ -179,7 +179,7 @@ relevant because we end up using it later. 37 00:02:07.244 --> 00:02:09.885 But they are indented because -they're inside the ifdef. +they're inside the #ifdef. 38 00:02:09.885 --> 00:02:13.287 @@ -209,7 +209,7 @@ at the docs for these two things. 43 00:02:29.383 --> 00:02:34.726 And I will warn you this, well especially -the MacOS 1 is a little bit funky, +the MacOS one is a little bit funky, 44 00:02:34.726 --> 00:02:39.917 @@ -275,7 +275,7 @@ with like read will return how many bytes 57 00:03:20.047 --> 00:03:21.306 -B Bytes were actually read. +were actually read. 58 00:03:21.306 --> 00:03:25.227 @@ -343,17 +343,17 @@ finally get successfully sent. 71 00:04:00.684 --> 00:04:03.737 Now how do we get this -actual byte sent value? +actual bytes_sent value? 72 00:04:03.737 --> 00:04:07.928 This is one of the ways where Linux and -macros APIs differ. +MacOS APIs differ. 73 00:04:07.928 --> 00:04:10.102 So in the Linux one, -send file just returns it. +sendfile just returns it. 74 00:04:10.102 --> 00:04:14.731 @@ -366,7 +366,7 @@ the return value was -1. 76 00:04:16.407 --> 00:04:20.089 -If it was sent failed, +If it was sent_failed, then Ok, fine, we break. 77 @@ -491,7 +491,7 @@ to make this error handling better. 102 00:05:37.607 --> 00:05:39.095 -This is not really specific to send file. +This is not really specific to sendfile. 103 00:05:39.095 --> 00:05:40.473 @@ -500,11 +500,11 @@ This is just in general. 104 00:05:40.473 --> 00:05:44.337 If we're writing to the socket, -and whether it's via send file or +and whether it's via sendfile or 105 00:05:44.337 --> 00:05:49.098 -via right and that operation fails after +via write and that operation fails after we've already sent some amount of data, 106 @@ -520,7 +520,7 @@ sending fail and we also need to know how 108 00:05:56.544 --> 00:06:00.522 many bytes were sent and the MacOS API for -this or the the BSC one. +this or the the BSD one. 109 00:06:00.522 --> 00:06:03.422 @@ -530,11 +530,11 @@ here we're actually doing 110 00:06:03.422 --> 00:06:08.134 basically the number of bytes that were -sent is actually equal to stats.st, +sent is actually equal to stats.st_size 111 00:06:08.134 --> 00:06:11.986 -size, or at least we're assuming +or at least we're assuming that as the starting point. 112 @@ -553,7 +553,7 @@ bytes that you want to send. 115 00:06:23.249 --> 00:06:27.289 -And then also, when we call send file, it +And then also, when we call sendfile, it will, after reading that to see how many 116 @@ -603,7 +603,7 @@ in other operating systems. 125 00:06:59.883 --> 00:07:02.597 A classic example of this that -happens today is IOU ring. +happens today is io_uring. 126 00:07:02.597 --> 00:07:03.836 @@ -630,7 +630,7 @@ It's just not available in Mac OS, 131 00:07:12.083 --> 00:07:14.488 they don't have a direct -equivalent of IOU ring. +equivalent of io_uring. 132 00:07:14.488 --> 00:07:18.983 @@ -639,12 +639,12 @@ platform like networking library, 133 00:07:18.983 --> 00:07:21.595 -that uses IOU ring, +that uses io_uring, what you end up with is. 134 00:07:21.595 --> 00:07:26.442 -If dev on Linux is huge because IOU ring +#ifdef on Linux is huge because io_uring is very different in terms of how it sets 135 @@ -741,7 +741,7 @@ website served locally, blazing fast. 154 00:08:28.776 --> 00:08:32.342 -[LAUGH] See about 300 lines of +[LAUGH] C about 300 lines of code that we built from scratch 155 diff --git a/en-US/2025-06-09-c-fundamentals/25-wrapping-up.txt b/en-US/2025-06-09-c-fundamentals/25-wrapping-up.txt index 0f05da88..0f38b5d6 100644 --- a/en-US/2025-06-09-c-fundamentals/25-wrapping-up.txt +++ b/en-US/2025-06-09-c-fundamentals/25-wrapping-up.txt @@ -7,7 +7,7 @@ Is just that memory is basically a gigantic array of bytes. They're all these ones and zeros, and you can choose to interpret them however you want. As the C programmers or other low level languages, not only can you interpret these however you want, but as we've seen, there are actually specific benefits. [00:00:32] -Especially when it comes to performance of making use of that understanding of the gigantic array of bytes, concept of memory. Granted, we are doing manual memory management there's the malloc and free and memory on the stack and buffer overruns and reading into garbage memory and all this initialized stuff. +Especially when it comes to performance of making use of that understanding of the gigantic array of bytes, concept of memory. Granted, we are doing manual memory management there's the malloc and free and memory on the stack and buffer overruns and reading into garbage memory and all this uninitialized stuff. [00:00:47] There's a lot of performance to be had, but also a ton a ton of foot guns. If you've ever thought pointers were hard, hopefully the fact that we just talked about memory addresses and integers a lot [LAUGH] will make that at least a little bit easier. But if anyone ever says pointer, and you're like, what's a pointer? @@ -46,10 +46,10 @@ This is how you would do this. So one of the reasons that I wanted to make sure This will tell you how to do that, and it's gonna be using exactly the same styles of docs and the types and all of that type of stuff that we learned about in this course. So if you want to go out and build your own Node.js add ons, let's say you're writing something like, I just really need some really high performance section here. [00:04:35] -If I could make this one part of my NodeJs server a little bit faster, this is a way you can do that. You can just bust out into C and do that. Or if you're like, I wanna write it in Rust, you could use C as an intermediary, because the Node.js API works in terms of C. +If I could make this one part of my Node.js server a little bit faster, this is a way you can do that. You can just bust out into C and do that. Or if you're like, I wanna write it in Rust, you could use C as an intermediary, because the Node.js API works in terms of C. [00:04:48] -They actually made their library compatible with C++, but C++ is a superset of C. So anything that works in C++, you can also do in C. I've actually gotten paid at work to write a Node.js add-on [LAUGH] before. So I can confirm that this definitely works with just C, you don't need to know C to use this. +They actually made their library compatible with C++, but C++ is a superset of C. So anything that works in C++, you can also do in C. I've actually gotten paid at work to write a Node.js C add-on [LAUGH] before. So I can confirm that this definitely works with just C, you don't need to know C++ to use this. [00:05:06] And essentially, this is a way that you can just speed up your your Node.js programs, or if you have some particular C library that you wanna use, that you wanna really get in there, and nobody's made a wrapper for that, you can totally do that. And in fact, you can even then distribute it on NPM. @@ -58,7 +58,7 @@ And essentially, this is a way that you can just speed up your your Node.js prog I did wanna note that if you're trying to get into a large C or C++ code base, such as like a Postgres or an operating system or something like that, building it can be a significant challenge. So for this course, we're dealing with one .c file, building it not difficult. [00:05:35] -If you're dealing with a gigantic C code base or C++ code base, building it, far from trivial. Fortunately, I do have a recommendation of how to learn about how to build these things. Andrew Kelley, who created Zig, gave this awesome talk called how to build software from source. +If you're dealing with a gigantic C code base or C++ code base, building it, far from trivial. Fortunately, I do have a recommendation of how to learn about how to build these things. Andrew Kelley, who created Zig, gave this awesome talk called "How to build software from source". [00:05:49] And depending on what programming language you're used to using, you might think that's easy. Why would you give a whole talk about that? It's not so easy when you're talking about large C and C++ projects. But if you watch this talk, he gives a lot of really, really good practical tips for how to actually configure and then build these large projects from source. @@ -67,7 +67,7 @@ And depending on what programming language you're used to using, you might think This is from the conference software you can love in 2023. And here is a link if you wanna go check that out. I also wanted to plug this book. This is a very famous book. I actually bought on eBay a copy. This is a picture of someone else's book. [00:06:21] -But if you ever hear what K&R, this is the book they're talking about. So this is Brian Curnahan and Dennis Ritchie. So Dennis Ritchie was a creative C, and then Brian is a very famous C user and writer and author and stuff like that. This is the first edition, which I did wanna make sure and get cuz it has some fun little anecdotes in here about really old hardware stuff that aren't really applicable anymore. +But if you ever hear what K&R, this is the book they're talking about. So this is Brian Kernighan and Dennis Ritchie. So Dennis Ritchie was a creative C, and then Brian is a very famous C user and writer and author and stuff like that. This is the first edition, which I did wanna make sure and get cuz it has some fun little anecdotes in here about really old hardware stuff that aren't really applicable anymore. [00:06:43] But this is also just kind of a seminal it's one of the classic books that people talk about, right up there with structure and interpretation of computer programs as just even beyond the C stuff. It's also got a lot of advice about philosophies around around writing programming, and as we seen in this workshop, philosophies around writing C code are pretty different from best practices in other languages. @@ -82,7 +82,7 @@ He's also got a little animated plane that flies across when you go to the homep I personally have read through the optimizing software in C++ one. Some of it in C++ specific, but a whole lot of it is really, really just like low level hardware. Like here's what your CPU is doing, here are some tips and tricks. Very, very, very detailed, pretty dense, but if you really wanna go down the rabbit hole on this stuff, and you thought that some of the crazy tricks that we did at the end of a part six were fun, you can find more stuff like that at this website. [00:08:00] -If you really wanna go all the way down the rabbit hole, Casey Muratore, who you might have seen on like the primogen stream. He's a frequent guest on there. He is an old school game engine programmer, and he made this unbelievably detailed course called performance aware programming. It is many, many, many hours, I've watched through all that. +If you really wanna go all the way down the rabbit hole, Casey Muratori, who you might have seen on like ThePrimeagen stream. He's a frequent guest on there. He is an old school game engine programmer, and he made this unbelievably detailed course called performance aware programming. It is many, many, many hours, I've watched through all that. [00:08:20] I don't think I'm quite caught up right now. But it goes into things like the very beginning of the course is you go through and build a simulator for a really old CPU. So you can actually see literally what is the CPU doing when it gets the ones and zeros in. @@ -98,7 +98,7 @@ And he actually goes through a debugger and steps into showing you all the layer [00:09:24] And I also wanted to mention, yeah, there was a question? ->> Speaker 2: Just on a similar vein, Mishko Avery, the creator of Angular, has a course on Frontend Masters called Bare Metal JavaScript. And he builds a CPU register and-. +>> Speaker 2: Just on a similar vein, Mishko Hevery, the creator of Angular, has a course on Frontend Masters called Bare Metal JavaScript. And he builds a CPU register and-. >> Richard Feldman: Nice. >> Speaker 2: Memory and all that kind of stuff from scratch. @@ -112,10 +112,10 @@ So, something to check out if you're already on Frontend Masters. Other than the name C, which I'm sure was like a pun on C and C++, it almost has nothing in common with C and a lot, a lot in common with Java. That's, I guess, a quick summary of it. [LAUGH] Yeah. Yeah, cool. So some low overhead C alternatives. [00:10:20] -We mentioned a couple of these, like C++ definitely way off the complexity into the spectrum, probably the most complicated popular language on the planet right now. Russ, strong contender, also extremely complicated language, but has way more guarantees and a lot of ergonomics benefits compared to C++. Also has the benefit of not having been created in 1980s so [LAUGH] got to benefit from a lot of advances in various things. +We mentioned a couple of these, like C++ definitely way off the complexity into the spectrum, probably the most complicated popular language on the planet right now. Rust, strong contender, also extremely complicated language, but has way more guarantees and a lot of ergonomics benefits compared to C++. Also has the benefit of not having been created in 1980s so [LAUGH] got to benefit from a lot of advances in various things. [00:10:44] -The D programming language is also pretty old. D is notable for like anytime you mention C++ or Russ or Zig on Hacker News, someone will be like, and D, what about D? But it's just not like really picking up as much steam. It's been around for a long time. +The D programming language is also pretty old. D is notable for like anytime you mention C++ or Rust or Zig on Hacker News, someone will be like, and D, what about D? But it's just not like really picking up as much steam. It's been around for a long time. [00:10:57] It's very powerful, has a lot of things, but it doesn't really seem, if I'm being honest, like it's gonna take off anytime soon. Zig is definitely like having a significant uptick in popularity by basically being a reaction to these sort of more complex C alternatives, like C++ and Rust and D and then Odin and JAI are two significantly less popular. @@ -127,7 +127,7 @@ But also, kind of taking the same basic approach of, yeah, let's try to improve He's made this programming language. JAI is specifically designed to be for games, and it's based on his frustrations with C++. And it has some significant differences between Zig and Odin, but I haven't actually used it, so I can't really comment on it in depth other than to say that right now on the simplest C alternatives, definitely Zig of these three is by far the most popular right now. [00:11:58] -And time will tell how those things shaken. Also all of these low overhead C Alternatives they all support C and Rob just like most mainstream languages do because C is the language that other languages use talk to each other as previously discussed. Like I mentioned earlier, I mean C is basically the most universal language in the world today and now that you know C you know the most universal in the world. +And time will tell how those things shakeout. Also all of these low overhead C Alternatives they all support C interop just like most mainstream languages do because C is the language that other languages use to talk to each other as previously discussed. Like I mentioned earlier, I mean C is basically the most universal language in the world today and now that you know C you know the most universal in the world. [00:12:22] Thanks very much. diff --git a/en-US/2025-06-09-c-fundamentals/25-wrapping-up.vtt b/en-US/2025-06-09-c-fundamentals/25-wrapping-up.vtt index 3f1784ca..2c1a358b 100644 --- a/en-US/2025-06-09-c-fundamentals/25-wrapping-up.vtt +++ b/en-US/2025-06-09-c-fundamentals/25-wrapping-up.vtt @@ -75,7 +75,7 @@ and reading into garbage memory and 16 00:00:46.478 --> 00:00:47.877 -all this initialized stuff. +all this uninitialized stuff. 17 00:00:47.877 --> 00:00:52.759 @@ -431,7 +431,7 @@ some really high performance section here. 90 00:04:35.112 --> 00:04:38.141 If I could make this one part of my -NodeJs server a little bit faster, +Node.js server a little bit faster, 91 00:04:38.141 --> 00:04:39.431 @@ -468,7 +468,7 @@ you can also do in C. 98 00:04:56.844 --> 00:05:01.134 I've actually gotten paid at work to -write a Node.js add-on [LAUGH] before. +write a Node.js C add-on [LAUGH] before. 99 00:05:01.134 --> 00:05:04.164 @@ -477,7 +477,7 @@ definitely works with just C, 100 00:05:04.164 --> 00:05:06.171 -you don't need to know C to use this. +you don't need to know C++ to use this. 101 00:05:06.171 --> 00:05:09.583 @@ -543,8 +543,8 @@ Andrew Kelley, who created Zig, 114 00:05:46.453 --> 00:05:49.701 -gave this awesome talk called how -to build software from source. +gave this awesome talk called "How +to build software from source". 115 00:05:49.701 --> 00:05:52.349 @@ -608,7 +608,7 @@ this is the book they're talking about. 128 00:06:25.033 --> 00:06:27.418 -So this is Brian Curnahan and +So this is Brian Kernighan and Dennis Ritchie. 129 @@ -753,12 +753,12 @@ find more stuff like that at this website. 158 00:08:00.231 --> 00:08:04.082 If you really wanna go all the way -down the rabbit hole, Casey Muratore, +down the rabbit hole, Casey Muratori, 159 00:08:04.082 --> 00:08:06.873 who you might have seen on -like the primogen stream. +like Theprimeagen stream. 160 00:08:06.873 --> 00:08:08.583 @@ -889,7 +889,7 @@ yeah, there was a question? 186 00:09:26.559 --> 00:09:31.609 >> Speaker 2: Just on a similar vein, -Mishko Avery, the creator of Angular, +Mishko Hevery, the creator of Angular, 187 00:09:31.609 --> 00:09:36.672 @@ -990,7 +990,7 @@ language on the planet right now. 208 00:10:29.654 --> 00:10:33.402 -Russ, strong contender, +Rust, strong contender, also extremely complicated language, but 209 @@ -1016,7 +1016,7 @@ is also pretty old. 213 00:10:47.329 --> 00:10:51.272 D is notable for like anytime you mention -C++ or Russ or Zig on Hacker News, +C++ or Rust or Zig on Hacker News, 214 00:10:51.272 --> 00:10:53.563 @@ -1120,21 +1120,21 @@ by far the most popular right now. 235 00:11:58.385 --> 00:12:03.048 And time will tell how -those things shaken. +those things shakeout. 236 00:12:03.048 --> 00:12:06.339 Also all of these low overhead -C Alternatives they all support C and +C Alternatives they all support C 237 00:12:06.339 --> 00:12:10.219 -Rob just like most mainstream languages +interop just like most mainstream languages do because C is the language that other 238 00:12:10.219 --> 00:12:13.190 -languages use talk to each +languages use to talk to each other as previously discussed. 239 diff --git a/en-US/2025-06-09-c-fundamentals/3-hello-world-using-printf.txt b/en-US/2025-06-09-c-fundamentals/3-hello-world-using-printf.txt index 3bad942c..66c3e4e0 100644 --- a/en-US/2025-06-09-c-fundamentals/3-hello-world-using-printf.txt +++ b/en-US/2025-06-09-c-fundamentals/3-hello-world-using-printf.txt @@ -35,7 +35,7 @@ Non zero generally means something went wrong, and then there's not really a ton But for learning purposes, I wanted to start with that cuz it's a little bit simpler. The other thing that we can do to improve the ergonomics of this is, instead of using this write function, we can use a wrapper around write called printf. And printf, as we will see later, the main reason that people use it, so this is print formatted, the f is for formatted. [00:03:20] -Again, normally we would probably see some camel case or some snake case [LAUGH] in these names, but this is C, 1972, they just went print, just stick an f on the end. It's the formatted version of print, really minimizing your teletype ink. And basically, this just takes the string. +Again, normally we would probably see some camel case or some snake case [LAUGH] in these names, but this is C, 1972, they just went printf, just stick an f on the end. It's the formatted version of print, really minimizing your teletype ink. And basically, this just takes the string. [00:03:35] And as previously mentioned, this will do things like automatically calculating the length of the string and automatically writing to standard out. So you don't have to say one for standard out and 13 for the length of the string, printf will just take care of that for you. Also, as we will see later in the course, printf has additional features that let you do some basic string interpolation type things. @@ -44,7 +44,7 @@ And as previously mentioned, this will do things like automatically calculating So if you wanted to like print a string in the middle of this without having to concatenate it together ahead of time, printf also lets you do that. You can also print numbers in here and it'll convert them to strings for you, things like that. So we're gonna use printf quite a bit more throughout the course of the course. [00:04:05] -But in terms of getting as close to the middle as possible, printf is just a convenience wrapper around write. Instead of coming from unisted, it comes from stdio, which is for standard input output. So usually, when you see a C Hello World example, they will show you this. +But in terms of getting as close to the metal as possible, printf is just a convenience wrapper around write. Instead of coming from unistd, it comes from stdio, which is for standard input output. So usually, when you see a C Hello World example, they will show you this. [00:04:22] This is almost exactly what you will see for C Hello World. It's like, int main, return 0, printf. But I did wanna go over, this is the actual closest to the metal version you can get without getting into operating system land. Okay, yeah, the F is for formatted, and formatted meaning, it supports the things like, if you wanna interpolate a string in there or a number or something like that. diff --git a/en-US/2025-06-09-c-fundamentals/3-hello-world-using-printf.vtt b/en-US/2025-06-09-c-fundamentals/3-hello-world-using-printf.vtt index 62fb6ce9..2329c7fd 100644 --- a/en-US/2025-06-09-c-fundamentals/3-hello-world-using-printf.vtt +++ b/en-US/2025-06-09-c-fundamentals/3-hello-world-using-printf.vtt @@ -324,7 +324,7 @@ probably see some camel case or 67 00:03:23.238 --> 00:03:27.691 some snake case [LAUGH] in these names, -but this is C, 1972, they just went print, +but this is C, 1972, they just went printf, 68 00:03:27.691 --> 00:03:29.043 @@ -396,7 +396,7 @@ more throughout the course of the course. 82 00:04:05.681 --> 00:04:09.454 But in terms of getting as close -to the middle as possible, +to the metal as possible, 83 00:04:09.454 --> 00:04:12.853 @@ -405,7 +405,7 @@ wrapper around write. 84 00:04:12.853 --> 00:04:16.503 -Instead of coming from unisted, +Instead of coming from unistd, it comes from stdio, which is for 85 diff --git a/en-US/2025-06-09-c-fundamentals/4-hello-world-in-c-exercise.txt b/en-US/2025-06-09-c-fundamentals/4-hello-world-in-c-exercise.txt index f5c88d84..724cd600 100644 --- a/en-US/2025-06-09-c-fundamentals/4-hello-world-in-c-exercise.txt +++ b/en-US/2025-06-09-c-fundamentals/4-hello-world-in-c-exercise.txt @@ -8,19 +8,19 @@ So I'm going to open up the first one here. This is a our first initial thing he So I am, this is my Zed code editor, if you haven't seen Zed before. It's awesome. It's written in Rust, so it is memory safe. [LAUGH] So basically, I'm just gonna cd into exercises. And now that I'm in exercises, if we want to just do a little LS, basically you've got exercises one through six. [00:00:43] -So we have six different sections here, all of this, 1.c2, .C, etc. And when you compile them, which I'm going to do in a second here, with this command that you can just copy paste out of the exercise. It's going to actually generate a different little binary here, on your disk. +So we have six different sections here, all of this, 1.c, 2.c, etc. And when you compile them, which I'm going to do in a second here, with this command that you can just copy paste out of the exercise. It's going to actually generate a different little binary here, on your disk. [00:00:56] -You can just delete those later if you want, but his is C. We compiled the binaries here. So when I paste this command and I say gcc-o app1, the -o means output. So this means output to app1. If you're on Windows, well, if you're on Windows, you should be using Windows Subsystem for Linux for this course. +You can just delete those later if you want, but this is C. We compiled the binaries here. So when I paste this command and I say gcc -o app1, the -o means output. So this means output to app1. If you're on Windows, well, if you're on Windows, you should be using Windows Subsystem for Linux for this course. [00:01:14] -But if you were doing Windows programming, you would actually say something app1.exe right here. Then you give it the name of the source file, which is o1.C, and then basically because I want to compile and then run. I'm telling GCC, which is the well technically GCC stands for the Goo C compiler, sorry, Goo Compiler Collection, yeah but it's used for C and C++. +But if you were doing Windows programming, you would actually say something app1.exe right here. Then you give it the name of the source file, which is 1.c, and then basically because I want to compile and then run. I'm telling GCC, which is the well technically GCC stands for the GNU C compiler, sorry, GNU Compiler Collection, yeah but it's used for C and C++. [00:01:37] It supports both. And actually on Mac OS, it's funny, this is actually not using GCC for real. It's just that GCC is so universal and so many build scripts rely on it, that actually Mac OS just aliases GCC to Clang, which is the actual compiler that Mac OS uses. [00:01:53] -And the way you can tell this is if you say GCC dash version, it's, this is Clang, which is kind of same exact thing if you say clang-version. But if you're on Linux or Windows Subsystem for Linux, then it's actual real GCC. So if you do GCC-version, you're gonna see something different than what I see on this Mac here. +And the way you can tell this is if you say GCC -version, it's, this is Clang, which is kind of same exact thing if you say clang -version. But if you're on Linux or Windows Subsystem for Linux, then it's actual real GCC. So if you do GCC -version, you're gonna see something different than what I see on this Mac here. [00:02:11] Anyway, so we're gonna build this and run it, and hey, it says hello world. Now I wanna call out your attention to something that it'll. It also says, there's this little weirdly formatted percent thing at the end here and this is actually part of the exercise. So the reason that that's happening is because we are printing out hello world without a new line at the end. @@ -32,7 +32,7 @@ And a lot of shells will, if the program runs and the program does not end in a But basically, this character is indicating hey, this program finished, and they wasn't a new line. But I'm going to put a new new line here anyway, because I don't want to put the prompt up here, because that'd look weird and actually, some shells will just put the prompt up here. [00:02:56] -This part will just start right here, because it's the program didn't end with a new line. But it's also quite common for them to say, hey, just so you know I'm inserting this new line here. The program itself did not actually end in a new line. So that's one of the things we're gonna change is we're gonna change this string to HelloWorld\end. +This part will just start right here, because it's the program didn't end with a new line. But it's also quite common for them to say, hey, just so you know I'm inserting this new line here. The program itself did not actually end in a new line. So that's one of the things we're gonna change is we're gonna change this string to HelloWorld\n. [00:03:13] So we're explicitly going to add in the new line. This is one of the things that Printf will do for you. So if you do printf, you don't actually need to put the new line there, printf will just automatically add the new line for you. But write will not, write is, I'm just gonna give you exactly this string. @@ -44,13 +44,13 @@ I'm gonna send that straight to standard out, no questions asked. So we're gonna Then we're going to have some fun. So the next thing we want to do is try making the length less than 14. What happens when you run the program? You can probably guess it doesn't print the entire string. And now try making the length longer than 14. You're not going to get a warning, you're not going to get an error. [00:03:55] -You're just going to see what happens. [LAUGH] Memory safety. Okay, so try uncommenting the next two lines as well as the include STDI at the top. So this is basically just switching it over from right to printf and we're gonna do a little bit of a actually interpolating a number in here. +You're just going to see what happens. [LAUGH] Memory safety. Okay, so try uncommenting the next two lines as well as the include STDI at the top. So this is basically just switching it over from write to printf and we're gonna do a little bit of a actually interpolating a number in here. [00:04:12] And then once you've got that working, which is just uncommenting that and then uncommenting up here, then you wanna try adding a second number named num2. And pick some other number to do it and print out both of the numbers. So when you do that, hint, you will need to make two changes to printf's arguments. [00:04:27] -You won't just need to change one of the arguments. And then finally, try having the program return something other than zero so you can just sort of see the exit code. So echo $?, is what you run in your terminal to see the output of your program. So after I do this, and then I do echo$?at print zero, because that is the exit code of the last program that I ran, which was the Hello World thing. +You won't just need to change one of the arguments. And then finally, try having the program return something other than zero so you can just sort of see the exit code. So echo $?, is what you run in your terminal to see the output of your program. So after I do this, and then I do echo $? it prints zero, because that is the exit code of the last program that I ran, which was the Hello World thing. [00:04:52] Okay, any questions about the exercises before we take some time. Yeah. @@ -65,7 +65,7 @@ So, yeah, what we're counting is semantic characters not source code characters, So let's get rid of that little missing trailing new line there. So to do that I'm just gonna delete these comments as I go so we can remember what we've done. So change the string to hello world with a new line, and then change the length to 14. [00:05:46] -Okay, great. And now we just don't see the percent sign anymore, because we actually have a new line there. Awesome. And now we're gonna make the length shorter, so we'll make it just 10, so that's HelloWorld and then once again, the percent sign is. Back, because we're not ending on a new line once again. +Okay, great. And now we just don't see the percent sign anymore, because we actually have a new line there. Awesome. And now we're gonna make the length shorter, so we'll make it just 10, so that's HelloWor and then once again, the percent sign is. Back, because we're not ending on a new line once again. [00:06:00] And now for the fun part, let's make it a lot longer. Boom, so we got hello world. And what is that stuff? What this is, is whatever happens to be in my binary after that string constant of Hello world, it's literally just spitting out whatever memory is in my executable. @@ -80,10 +80,10 @@ No problem. If you just got an integer wrong, if I bump it all the way up to 200 That might just be because there's nothing printable there. A lot of these characters are not printable in the terminal. Just kind of silently mess that up. I don't know if it'll let me make be this long. Cool. Yeah, so now we've got lots of memory. Look at that. [00:07:00] -This is all sorts of stuff that's in my binary, so, yeah. This is hello world program, really doing a good job dumping all the secrets. We can see, here's the name of our program. That's in there for some reason. BOF, I don't know what that is. There's are all just random 0s and 1s that are being interpreted by the terminal as being text, although, obviously a lot of these are not text Text. +This is all sorts of stuff that's in my binary, so, yeah. This is hello world program, really doing a good job dumping all the secrets. We can see, here's the name of our program. That's in there for some reason. BOF, I don't know what that is. There's are all just random 0s and 1s that are being interpreted by the terminal as being text, although, obviously a lot of these are not text. [00:07:20] -They're just random 1s and 0s, gibberish, in some cases, white space, whatnot. Let's see if we can get the program to crash from doing this. It's kinda hard just happily spitting out all this memory. As you can see the level of memory safety we're doing, and we're going to see plenty more examples of this as we go. +They're just random 1s and 0s, gibberish, in some cases, white space, whatnot. Let's see if we can get the program to crash from doing this. It's kinda hard just happily spitting out all this memory. As you can see this is the level of memory safety we're doing, and we're going to see plenty more examples of this as we go. [00:07:39] But there was no compiler warnings here. There's no errors. There's no nothing. But if we did use printf, at least this particular error, we would not be susceptible to. This only happened because I was intentionally using a number other than 14 to demonstrate what happens if you get your math a little bit wrong when it comes to C. @@ -92,7 +92,7 @@ But there was no compiler warnings here. There's no errors. There's no nothing. And in the next section, we'll talk about a little bit more about what's going on under the hood there that makes this happen. Okay, so now let's get into the more ergonomic world. So if I just uncomment those two lines, int num=42, then it's going to be, hey, wait a minute. [00:08:07] -Call the undeclared library function printf. What's going on with that? So, okay, I just need to uncomment that and now we are actually importing that because this unisted.h is where Write comes from and printf comes from stduio. So now if I print this, it's going to say, hello world, followed by the number is 42. +Call the undeclared library function printf. What's going on with that? So, okay, I just need to uncomment that and now we are actually importing that because this unistd.h is where Write comes from and printf comes from stdio. So now if I print this, it's going to say, hello world, followed by the number is 42. [00:08:27] And if I want to print out a second number let's say we do you know num=2 I don't know 45. Then I can't just do this because if I do this, then it's gonna be like okay, well, didn't change anything. And I also can't do this, I can't just stick an extra num2 in there. @@ -101,7 +101,7 @@ And if I want to print out a second number let's say we do you know num=2 I don' It's just going to give me a warning of, hey, wait a minute, data argument not used by format string. This is something about the compiler actually having some awareness of what printf is because it's part of the standard library. So if I run this, I will get a little warning here, but it's going to happily just do the same thing. [00:08:58] -Basically the second argument is going can be totally ignored. The second number is %d. I don't need another newline there, whoops. Printf will do that for me. My bad, printf doesn't do that. I think you print line from Rust, my mistake. So yeah, second number is 45, great, and basically, if I want, I can change this to be something else, percent s for a string, and then it's going to complain wait a minute, wait a minute, you said this is an int, but it's not. +Basically the second argument is going can be totally ignored. The second number is %d. I don't need another newline there, whoops. Printf will do that for me. My bad, printf doesn't do that. I think you print line from Rust, my mistake. So yeah, second number is 45, great, and basically, if I want, I can change this to be something else, %s for a string, and then it's going to complain wait a minute, wait a minute, you said this is an int, but it's not. [00:09:28] However, it'll still actually let me run it. It just might crash the program. This is a really fun error to get in your C code. Segmentation fault. You might notice the absence of a stack trace. You don't get one if you If you do a segmentation fault. Segmentation fault just basically means your program tried to read memory that it doesn't have permission to read according to the operating system. @@ -119,18 +119,18 @@ But you do notice that, unlike in some other languages, this is just considered Bad things are gonna happen. C is, no, if you're sure, go ahead. You can feel free to run the program, it might segfault or do whatever. But yeah, even though it knows it's not going to block you, it's just going let you go ahead and do your thing. [00:10:48] -Okay, moving on. Yeah, so we've had two different numbers and then finally, yeah, we can just return something other than 0, we can return 11. And now if I echo$?, it says 11. Any questions about the exercise? +Okay, moving on. Yeah, so we've had printf both numbers and then finally, yeah, we can just return something other than 0, we can return 11. And now if I echo$?, it says 11. Any questions about the exercise? >> Speaker 3: I have one that might be just pedantic with the language itself. [00:11:08] -Is it worth anything to recast an intuit string? Can you do that? Are variables mutable in that way or is the juice not really worth the squeeze? +Is it worth anything to recast an int to a string? Can you do that? Are variables mutable in that way or is the juice not really worth the squeeze? >> Richard Feldman: Can you recast a, okay, so the terminology here is important. I wouldn't say, well, okay, so certainly you can recast an integer to a string. [00:11:28] But what that would mean is, essentially, let's take this integer and let's pretend that the 1s and 0s in memory that represent that integer. We're just gonna reinterpret them and pretend that they're actually the 1s and 0s of a string. You can do that, and in fact, we actually are going to do that in this workshop, that's what C calls casting. [00:11:44] -There's a separate thing you can do, which is converting, where you're actually gonna say, okay, I've got an integer and I want a string. Basically, you just call a function that says, turn this integer into a string, and it will do that for you. So we could do that, but honestly, idiomatically, I would just choose to use Print off to do that. +There's a separate thing you can do, which is converting, where you're actually gonna say, okay, I've got an integer and I want a string. Basically, you just call a function that says, turn this integer into a string, and it will do that for you. So we could do that, but honestly, idiomatically, I would just choose to use printf to do that. [00:11:59] Because explicitly going out of your way to convert that is more work than necessary if this is just what all you're going to do with it anyway. @@ -146,16 +146,16 @@ Because explicitly going out of your way to convert that is more work than neces >> Speaker 4: Into our binary-. >> Richard Feldman: Yeah >> Speaker 4: Or can we pick just the right function? ->> Richard Feldman: So we're gonna talk about this more later, but literally, what pound include does is copy paste. So running this line of code is exactly the same thing as taking the contents of stdio.h, and pasting them into your file. +>> Richard Feldman: So we're gonna talk about this more later, but literally, what #include does is copy paste. So running this line of code is exactly the same thing as taking the contents of stdio.h, and pasting them into your file. [00:12:34] -That's what pound include does. You might be wondering about, well, hang on a sec. What if I have,, that thing which depends on something else, and then I also depend on that something else? Is it going to get pasted multiple times? The answer is yes, but each of these files that I'm depending on does have a little bit of logic that uses different preprocessor macros to basically say. +That's what #include does. You might be wondering about, well, hang on a sec. What if I have, that thing which depends on something else, and then I also depend on that something else? Is it going to get pasted multiple times? The answer is yes, but each of these files that I'm depending on does have a little bit of logic that uses different preprocessor macros to basically say. [00:12:55] -Don't include myself semantically twice, even though the text is included twice. One of the things that the designers of Go wanted to do better based on their experiences with C, which some of them co-created. Was that they wanted to basically do a better job with imports and stuff that to make it more of a first class semantic thing so you can make some of the ergonomics around this better. +Don't include myself semantically twice, even though the text is included twice. One of the things that the designers of Go wanted to do better based on their experiences with C, which some of them co-created. Was that they wanted to basically do a better job with imports and stuff like that to make it more of a first class semantic thing so you can make some of the ergonomics around this better. [00:13:16] -This is actually one of the reasons that C, especially C++ have worse compile times than they otherwise would. Is just, the semantics of how include work. I did want to mention, I think, in the previous question, I didn't address one implication of something you're asking, which was. What happens if there's 100 different functions in std.io, .h, but I'm only using one of them, what happens the other ones? +This is actually one of the reasons that C, especially C++ have worse compile times than they otherwise would. Is just, the semantics of how include work. I did want to mention, I think, in the previous question, I didn't address one implication of something you're asking, which was. What happens if there's 100 different functions in stdio.h, but I'm only using one of them, what happens to the other ones? [00:13:38] The C compiler actually doesn't deal with that. But basically there's a step after compilation called linking, which we're not really going to cover in this course because when I do GCC, it automatically takes care of doing that separately. But basically what linking does is it deals with after you've compiled your source code into the binary executable, there's this extra step. diff --git a/en-US/2025-06-09-c-fundamentals/4-hello-world-in-c-exercise.vtt b/en-US/2025-06-09-c-fundamentals/4-hello-world-in-c-exercise.vtt index 9bf06d2e..9f3f3462 100644 --- a/en-US/2025-06-09-c-fundamentals/4-hello-world-in-c-exercise.vtt +++ b/en-US/2025-06-09-c-fundamentals/4-hello-world-in-c-exercise.vtt @@ -80,7 +80,7 @@ exercises one through six. 17 00:00:43.594 --> 00:00:48.000 So we have six different sections here, -all of this, 1.c2, .C, etc. +all of this, 1.c, 2.c, etc. 18 00:00:48.000 --> 00:00:50.500 @@ -104,7 +104,7 @@ on your disk. 22 00:00:56.953 --> 00:00:59.442 You can just delete those later -if you want, but his is C. +if you want, but this is C. 23 00:00:59.442 --> 00:01:00.807 @@ -113,7 +113,7 @@ We compiled the binaries here. 24 00:01:00.807 --> 00:01:06.476 So when I paste this command and -I say gcc-o app1, the -o means output. +I say gcc -o app1, the -o means output. 25 00:01:06.476 --> 00:01:08.974 @@ -141,7 +141,7 @@ something app1.exe right here. 30 00:01:19.103 --> 00:01:22.073 Then you give it the name of -the source file, which is o1.C, and +the source file, which is 1.c, and 31 00:01:22.073 --> 00:01:24.567 @@ -155,8 +155,8 @@ technically GCC stands for 33 00:01:29.717 --> 00:01:34.284 -the Goo C compiler, sorry, -Goo Compiler Collection, +the GNU C compiler, sorry, +GNU Compiler Collection, 34 00:01:34.284 --> 00:01:37.217 @@ -189,12 +189,12 @@ compiler that Mac OS uses. 40 00:01:53.852 --> 00:01:58.209 And the way you can tell this is if you -say GCC dash version, it's, this is Clang, +say GCC -version, it's, this is Clang, 41 00:01:58.209 --> 00:02:01.277 which is kind of same exact -thing if you say clang-version. +thing if you say clang -version. 42 00:02:01.277 --> 00:02:04.828 @@ -207,7 +207,7 @@ Linux, then it's actual real GCC. 44 00:02:07.592 --> 00:02:08.711 -So if you do GCC-version, +So if you do GCC -version, 45 00:02:08.711 --> 00:02:11.641 @@ -317,7 +317,7 @@ change is we're gonna change this string 67 00:03:12.529 --> 00:03:13.508 -to HelloWorld\end. +to HelloWorld\n. 68 00:03:13.508 --> 00:03:16.488 @@ -421,7 +421,7 @@ at the top. 89 00:04:05.344 --> 00:04:08.497 So this is basically just switching -it over from right to printf and +it over from write to printf and 90 00:04:08.497 --> 00:04:12.007 @@ -474,7 +474,7 @@ to see the output of your program. 100 00:04:41.874 --> 00:04:46.885 So after I do this, and then I do -echo$?at print zero, because that is +echo $? it prints zero, because that is 101 00:04:46.885 --> 00:04:52.326 @@ -605,7 +605,7 @@ shorter, so we'll make it just 10, so 129 00:05:55.775 --> 00:05:58.426 -that's HelloWorld and +that's HelloWor and then once again, the percent sign is. 130 @@ -754,7 +754,7 @@ are being interpreted by the terminal as 161 00:07:16.368 --> 00:07:20.100 being text, although, obviously -a lot of these are not text Text. +a lot of these are not text. 162 00:07:20.100 --> 00:07:26.616 @@ -773,7 +773,7 @@ spitting out all this memory. 165 00:07:34.057 --> 00:07:36.561 -As you can see the level of +As you can see this is the level of memory safety we're doing, and 166 @@ -856,8 +856,8 @@ and now we are actually importing that 183 00:08:17.496 --> 00:08:22.395 -because this unisted.h is where Write -comes from and printf comes from stduio. +because this unistd.h is where Write +comes from and printf comes from stdio. 184 00:08:22.395 --> 00:08:27.343 @@ -950,7 +950,7 @@ basically, if I want, I can change this to 203 00:09:21.259 --> 00:09:25.387 -be something else, percent s for a string, +be something else, %s for a string, and then it's going to complain wait 204 @@ -1104,7 +1104,7 @@ Okay, moving on. 236 00:10:51.748 --> 00:10:55.011 -Yeah, so we've had two different +Yeah, so we've had printf both numbers and then finally, yeah, 237 @@ -1128,7 +1128,7 @@ just pedantic with the language itself. 241 00:11:08.670 --> 00:11:12.581 Is it worth anything to -recast an intuit string? +recast an int to a string? 242 00:11:12.581 --> 00:11:13.311 @@ -1208,7 +1208,7 @@ honestly, idiomatically, 258 00:11:57.287 --> 00:11:59.691 I would just choose to -use Print off to do that. +use printf to do that. 259 00:11:59.691 --> 00:12:02.807 @@ -1266,8 +1266,8 @@ talk about this more later, but 271 00:12:22.054 --> 00:12:25.455 -literally, what pound -include does is copy paste. +literally, what +#include does is copy paste. 272 00:12:25.455 --> 00:12:29.888 @@ -1281,7 +1281,7 @@ pasting them into your file. 274 00:12:34.253 --> 00:12:36.737 -That's what pound include does. +That's what #include does. 275 00:12:36.737 --> 00:12:38.507 @@ -1290,7 +1290,7 @@ well, hang on a sec. 276 00:12:38.507 --> 00:12:41.372 -What if I have,, that thing which +What if I have, that thing which depends on something else, and 277 @@ -1333,7 +1333,7 @@ do a better job with imports and 285 00:13:11.060 --> 00:13:14.026 -stuff that to make it more of +stuff like that to make it more of a first class semantic thing so 286 @@ -1369,12 +1369,12 @@ something you're asking, which was. 292 00:13:32.124 --> 00:13:35.772 What happens if there's 100 -different functions in std.io, .h, +different functions in stdio.h, 293 00:13:35.772 --> 00:13:38.902 but I'm only using one of them, -what happens the other ones? +what happens to the other ones? 294 00:13:38.902 --> 00:13:41.958 diff --git a/en-US/2025-06-09-c-fundamentals/5-numbers-in-memory.txt b/en-US/2025-06-09-c-fundamentals/5-numbers-in-memory.txt index cc77d5f0..7603e08e 100644 --- a/en-US/2025-06-09-c-fundamentals/5-numbers-in-memory.txt +++ b/en-US/2025-06-09-c-fundamentals/5-numbers-in-memory.txt @@ -2,7 +2,7 @@ >> Richard feldman: Building HTTP responses. In this section, we're going to start building our actual static web server. We're not gonna start by having it up and running, listening on port 8080, whatever. We're just gonna do it a much simpler way, where at first we're just gonna work with strings. [00:00:15] -So we're gonna build HTTP responses first, and then the next section we're gonna work with dealing with the incoming HTTP requests, still just working with strings. Then we're gonna get into file IO, cuz one of the things that static web server needs to do is to read the files off your disc. +So we're gonna build HTTP responses first, and then the next section we're gonna work with dealing with the incoming HTTP requests, still just working with strings. Then we're gonna get into file IO, cuz one of the things that static web server needs to do is to read the files off your disk. [00:00:27] And then finally, we're gonna get to the network IO portion of this. So for now, we're just gonna start off working with strings and learn a little bit more about how C deals with string manipulation and learn a little bit more about the language as we go. So we're gonna start off by talking about numbers in memory. @@ -20,7 +20,7 @@ The CPU just has instructions that basically say like, hey, tell me some ones an And it's like, sure, here are the ones and zeros that come out of adding those two together. You could also say the same exact pattern of ones and zeros. Hey, CPU, please treat these as a floating point number and do floating point multiplication or division on them, or something like that. [00:01:42] -And the CPU is like, sure, you're the ones and zeros that come out if you do that. Or you could say, treat it as a string, and I'm gonna do something else with it. But most commonly, these ones and zeros are actually grouped into groups of eight, at least in modern hardware. +And the CPU is like, sure, here are the ones and zeros that come out if you do that. Or you could say, treat it as a string, and I'm gonna do something else with it. But most commonly, these ones and zeros are actually grouped into groups of eight, at least in modern hardware. [00:01:53] So 8-bits to a byte. So 8 individual 1s and 0s correspond to 1-byte. And in modern hardware, this is sort of emerged as the standard, where you basically have like, if you're working with memory, you're generally working in terms of bytes. When we specified 13 or 14 as the length of the Hello World string in the last exercise, that was 13 or 14-bytes. @@ -71,7 +71,7 @@ So we flip over to one more. We add one more digit over in the next column, over For example, instead of interpreting them in groups of eight, where we have like, this is the number 0. This is the number 1. This is 2, and this is 3. We can say, okay, I'm actually gonna take these same exact pattern of 1s and 0s and I'm gonna chop it up differently. [00:06:06] -And I'm gonna say, well, actually, I wanna chop it right in the middle here. Instead of having groups of 8, I'm gonna have like groups of 16 and this one is gonna be 1, and then this one's gonna be,1027. Or chop it up in the middle here, and say sorry, and not chop up at all, and just say, this is one gigantic number. +And I'm gonna say, well, actually, I wanna chop it right in the middle here. Instead of having groups of 8, I'm gonna have like groups of 16 and this one is gonna be 1, and then this one's gonna be,1027. Or chop it up in the middle here, and say... Sorry, and not chop up at all, and just say, this is one gigantic number. [00:06:21] And so this, this whole thing is like, this one right here gives us 131072, this one gives us 1024, and this, two 1s at the end give us 3, just like they did back up here. And now we have some gigantic integer. So this is a way that you can take exactly the same piece of memory and represents it in multiple different ways. diff --git a/en-US/2025-06-09-c-fundamentals/5-numbers-in-memory.vtt b/en-US/2025-06-09-c-fundamentals/5-numbers-in-memory.vtt index 4796faaf..8ffd8347 100644 --- a/en-US/2025-06-09-c-fundamentals/5-numbers-in-memory.vtt +++ b/en-US/2025-06-09-c-fundamentals/5-numbers-in-memory.vtt @@ -41,7 +41,7 @@ of the things that static web server needs 9 00:00:25.738 --> 00:00:27.349 -to do is to read the files off your disc. +to do is to read the files off your disk. 10 00:00:27.349 --> 00:00:30.558 @@ -176,7 +176,7 @@ division on them, or something like that. 37 00:01:42.644 --> 00:01:45.336 -And the CPU is like, sure, you're the ones +And the CPU is like, sure, here are the ones and zeros that come out if you do that. 38 @@ -628,7 +628,7 @@ then this one's gonna be,1027. 133 00:06:16.271 --> 00:06:19.523 Or chop it up in the middle here, and -say sorry, and not chop up at all, and +say... Sorry, and not chop up at all, and 134 00:06:19.523 --> 00:06:21.325 diff --git a/en-US/2025-06-09-c-fundamentals/6-byte-arrays.txt b/en-US/2025-06-09-c-fundamentals/6-byte-arrays.txt index f1b35be8..bde908b4 100644 --- a/en-US/2025-06-09-c-fundamentals/6-byte-arrays.txt +++ b/en-US/2025-06-09-c-fundamentals/6-byte-arrays.txt @@ -1,5 +1,5 @@ [00:00:00] ->> Richard Feldman: So if we go back and apply this concept to Hello, World, one of the things that might surprise you is that when we're doing this write call, and we're passing in 1, that was actually a 32-bit integer. So that was 32 ones and zeros, which was to say, the bottom one that we had on the previous slide. +>> Richard Feldman: So if we go back and apply this concept to Hello World, one of the things that might surprise you is that when we're doing this write call, and we're passing in 1, that was actually a 32-bit integer. So that was 32 ones and zeros, which was to say, the bottom one that we had on the previous slide. [00:00:17] That basically means that if you want to, you can specify up to 2 to the 32 different numbers in that. And that gets you up to things like 4 billion or something like that. Is the highest number you can express in a 32-bit integer. If you wanna go higher than that, you would need to actually reserve more bits in memory. @@ -29,7 +29,7 @@ Original ASCII did use, in fact, 1-byte per character. And actually, fortunately Now, as it turns out, American English is not all the languages in the world. There's actually others. And so yeah, this is where we got Unicode. And fortunately, there was this really, really clever encoding. And it's required that if you ever introduce someone to the concept of UTF-8, you have to explain how clever this is. [00:03:05] -But they managed to mix an encoding that was backwards and compatible with ASCII, which is basically if we were to look at Unicode characters here, this stuff that we have right here, this is both ASCII and valid UTF-8. Because UTF-8 cleverly said for all of the first 256 characters that we support in UTF-8, we're gonna choose to have them be exactly the same as ASCII. +But they managed to mix an encoding that was backwards compatible with ASCII, which is basically if we were to look at Unicode characters here, this stuff that we have right here, this is both ASCII and valid UTF-8. Because UTF-8 cleverly said for all of the first 256 characters that we support in UTF-8, we're gonna choose to have them be exactly the same as ASCII. [00:03:28] So UTF-8 is totally backwards compatible with ASCII. If you have some program that was using ASCII for its strings in the 1970s and you decide to upgrade UTF-8, all of that code will still just completely work as is, because UTF-8 represents those strings exactly the same way in memory. diff --git a/en-US/2025-06-09-c-fundamentals/6-byte-arrays.vtt b/en-US/2025-06-09-c-fundamentals/6-byte-arrays.vtt index bb0fce05..7e783820 100644 --- a/en-US/2025-06-09-c-fundamentals/6-byte-arrays.vtt +++ b/en-US/2025-06-09-c-fundamentals/6-byte-arrays.vtt @@ -3,7 +3,7 @@ WEBVTT 1 00:00:00.031 --> 00:00:03.188 >> Richard Feldman: So if we go back and -apply this concept to Hello, World, +apply this concept to Hello World, 2 00:00:03.188 --> 00:00:07.896 @@ -269,7 +269,7 @@ you have to explain how clever this is. 56 00:03:05.601 --> 00:03:10.542 But they managed to mix an encoding that -was backwards and compatible with ASCII, +was backwards compatible with ASCII, 57 00:03:10.542 --> 00:03:14.479 diff --git a/en-US/2025-06-09-c-fundamentals/7-string-length-null-termination.txt b/en-US/2025-06-09-c-fundamentals/7-string-length-null-termination.txt index 01a65f91..a2a2f8fc 100644 --- a/en-US/2025-06-09-c-fundamentals/7-string-length-null-termination.txt +++ b/en-US/2025-06-09-c-fundamentals/7-string-length-null-termination.txt @@ -5,7 +5,7 @@ I'm assuming that we're using the HTTP/1.1 protocol, which is extremely widely supported. HTTP/2 is much fancier. We are not gonna support HTTP/2 in our static web server, number one, because we don't need to. And number two, because it's way more complicated and would take way longer to explain. [00:00:36] -So we're just gonna stick with classic HTTP/1.1. The next thing it's gonna do is it's gonna have a blank line. And then it's gonna say doctype html, blah, blah, blah, basically the entire context of the index side html there. This is literally what comes back from the server. +So we're just gonna stick with classic HTTP/1.1. The next thing it's gonna do is it's gonna have a blank line. And then it's gonna say doctype html, blah, blah, blah, basically the entire context of the index.html there. This is literally what comes back from the server. [00:00:49] It's this string, new line, this string. It's all one gigantic string, that's it. It's not JSON or anything like that, it's just this format. If we were to represent this header right here, HTTP/1.1 200 OK in bytes in memory, again, it would be like, okay, well, H is 72 in ASCII, which means it's also in UTF-8, which is what web servers use. @@ -59,16 +59,16 @@ It's an integer representing the memory address of the beginning of that array. So NULL meaning 0 in this case, not to be confused with null in JavaScript sense, which is its own semantic thing. Here NULL just means 0 byte, as opposed to 0 character. So NULL-terminated just means this is a string that has a 0 byte at the very end of it. [00:06:10] -And yeah, you might be saying, isn't strlen incredibly slow for something like C? Well, yes, so why don't you destroy the length up front? Then you wouldn't have to deal with this fancy like, well, performance optimization only works if it's known at compile time. At runtime, if we got this value and the string came in from a user, then we'd have to march over the whole thing. +And yeah, you might be saying, isn't strlen incredibly slow for something like C? Well, yes, so why don't you store the length up front? Then you wouldn't have to deal with this fancy like, well, performance optimization only works if it's known at compile time. At runtime, if we got this value and the string came in from a user, then we'd have to march over the whole thing. [00:06:31] Yeah, it would be more efficient in terms of getting the length of a string to store the length up front. But again, you've got to remember, 1972 design decisions, right? When you're this limited on memory, it can potentially make sense to say, well, instead of storing a 32 or 64 bit length with every single string that you're passing around, maybe we wanna just store one byte. [00:06:50] -And yeah, it's gonna take longer to traverse the string to ask about its length is. But at least you are reducing your overall memory usage compared to passing around the length every single time, or storing it alongside the string. So it's sort of like pre-computing the length. Having said that, I also have heard people say that even in 1972 this was the wrong trade off to make, but I wasn't there, I wasn't even born yet, so who am I to say? +And yeah, it's gonna take longer to traverse the string to ask about what its length is. But at least you are reducing your overall memory usage compared to passing around the length every single time, or storing it alongside the string. So it's sort of like pre-computing the length. Having said that, I also have heard people say that even in 1972 this was the wrong trade off to make, but I wasn't there, I wasn't even born yet, so who am I to say? [00:07:14] -But that's kind of the reasoning for this. When you encounter C APIs in the wild, even the node, JSC API, it's still doing stuff like expecting NULL-terminated strings and stuff. So even though this design decision hasn't really aged very well in terms of what's performant in a good trade off in terms of CPU cycles and memory. +But that's kind of the reasoning for this. When you encounter C APIs in the wild, even the Node.js C API, it's still doing stuff like expecting NULL-terminated strings and stuff. So even though this design decision hasn't really aged very well in terms of what's performant in a good trade off in terms of CPU cycles and memory. [00:07:32] It's still like a whole lot of C APIs will use NULL-terminated strings and say, you gotta give me a NULL-terminated string right here. Okay, yes, but at least in this case, where we're using static hard coded thing, at least it will get optimized away. So that will just become a 15. @@ -107,7 +107,7 @@ You can decide that it's integers that are 8-bits, 16-bits, 32-bits, 64-bits. Or But it's not gonna give us a nice error message, that's for sure, it's just gonna interpret them incorrectly. We talked about byte arrays, so we can have just back-to-back bytes, and then we can index into those, just like the global array of memory. Talked about null-terminated strings, where the 0 byte at the end of the string, not to be confused with 0 the character, which is not a 0 byte. [00:10:58] -But 0 terminated strings are essentially a way to be able to just pass this memory address to something and have it actually without any other information, nowhere the string ends. And then finally how getting a string's length is a little bit inefficient. Maybe a design decision that hasn't aged well since 1972, but if it's a hard coded string, it will get inlined. +But 0 terminated strings are essentially a way to be able to just pass this memory address to something and have it actually without any other information, know where the string ends. And then finally how getting a string's length is a little bit inefficient. Maybe a design decision that hasn't aged well since 1972, but if it's a hard coded string, it will get inlined. [00:11:19] And if worse comes to worse, you can also just explicitly pass around the length separately. Then some functions, such as write will say, I'm not gonna traverse and go look for the null-terminated. You just give me the length and I'll just assume that's how many you want. diff --git a/en-US/2025-06-09-c-fundamentals/7-string-length-null-termination.vtt b/en-US/2025-06-09-c-fundamentals/7-string-length-null-termination.vtt index fda8fa61..b4affab9 100644 --- a/en-US/2025-06-09-c-fundamentals/7-string-length-null-termination.vtt +++ b/en-US/2025-06-09-c-fundamentals/7-string-length-null-termination.vtt @@ -78,7 +78,7 @@ blah, blah, blah, 17 00:00:44.513 --> 00:00:47.443 basically the entire context -of the index side html there. +of the index.html there. 18 00:00:47.443 --> 00:00:49.191 @@ -576,7 +576,7 @@ something like C? 122 00:06:15.051 --> 00:06:18.165 Well, yes, so -why don't you destroy the length up front? +why don't you store the length up front? 123 00:06:18.165 --> 00:06:21.699 @@ -630,7 +630,7 @@ maybe we wanna just store one byte. 133 00:06:50.463 --> 00:06:53.558 And yeah, it's gonna take longer to -traverse the string to ask about its +traverse the string to ask about what its 134 00:06:53.558 --> 00:06:54.073 @@ -668,7 +668,7 @@ But that's kind of the reasoning for this. 141 00:07:16.062 --> 00:07:19.613 When you encounter C APIs in the wild, -even the node, JSC API, +even the Node.js C API, 142 00:07:19.613 --> 00:07:24.043 @@ -982,7 +982,7 @@ address to something and 206 00:11:04.836 --> 00:11:09.057 have it actually without any other -information, nowhere the string ends. +information, know where the string ends. 207 00:11:09.057 --> 00:11:12.279 diff --git a/en-US/2025-06-09-c-fundamentals/8-strings-memory-exercise.txt b/en-US/2025-06-09-c-fundamentals/8-strings-memory-exercise.txt index 01e8def6..4c01c527 100644 --- a/en-US/2025-06-09-c-fundamentals/8-strings-memory-exercise.txt +++ b/en-US/2025-06-09-c-fundamentals/8-strings-memory-exercise.txt @@ -2,22 +2,22 @@ >> Richard Feldman: Let's do the exercise for part 2. So moving on right here. Let's close one, okay, so first we're gonna once again build and run the program. So, I'm just gonna copy and paste this I'm gonna leave that one open just in case we wanna refer to it later, oops. [00:00:16] -I need to go into the exercises again, hmm, okay. So essentially, what we're seeing here is that HTTP, 1.1 200 okay, and it says that output was from right, and this is from printf. And then here's the same thing, and let's go take a look at what the differences are in there. +I need to go into the exercises again, hmm, okay. So essentially, what we're seeing here is that HTTP, 1.1 200 okay, and it says that output was from write, and this is from printf. And then here's the same thing, and let's go take a look at what the differences are in there. [00:00:33] -So first it says, let's try replacing this number 15 with a call to strlen and then you have to remember to include string.h above. So, this is essentially going to be like calling right just like we did before, but now that we've made header be a variable. Let's actually just use strlen instead of like hard coding the length like we did in part one. +So first it says, let's try replacing this number 15 with a call to strlen and then you have to remember to include string.h above. So, this is essentially going to be like calling write just like we did before, but now that we've made header be a variable. Let's actually just use strlen instead of like hard coding the length like we did in part one. [00:00:53] After you're done using that, now try introducing a null terminator in the middle of the string. So C allows you to write backslash zero and what backslash zero means kind of similar, like how backslash n is a new line. Backslash zero is basically like write a zero byte at this exact point, you can do this anywhere you wanted a string. [00:01:10] -So, for example, like you could put it right after the HTTP, sorry, HTTP and HTTP, and just say backslash zero right there, and you might be able to predict what that's going to do. But try to make a guess of what you think it's gonna do before you actually run the program and then run it and see what happens. +So, for example, like you could put it right after the HTTT, sorry, HTT in HTTP, and just say backslash zero right there, and you might be able to predict what that's going to do. But try to make a guess of what you think it's gonna do before you actually run the program and then run it and see what happens. [00:01:27] -Okay, and then we have the second thing that's like, hey, that output was from right, this is from printf. And now we can try changing the %s here to %zud, there's gonna be a little compiler warning, but you can just ignore that and that's gonna print out the memory address. +Okay, and then we have the second thing that's like, hey, that output was from write, this is from printf. And now we can try changing the %s here to %zud, there's gonna be a little compiler warning, but you can just ignore that and that's gonna print out the memory address. [00:01:38] -We can actually see what that is and that's gonna be different depending on what machine you're running on, potentially. And then finally, try changing this back to percent s, and then replace the printfs last argument, which was right now header, with this argument instead. And then also try it with the number zero instead of that number and you can see some interesting stuff for what those prints. +We can actually see what that is and that's gonna be different depending on what machine you're running on, potentially. And then finally, try changing this back to percent s, and then replace the printf's last argument, which was right now header, with this argument instead. And then also try it with the number zero instead of that number and you can see some interesting stuff for what those prints. [00:02:04] @@ -27,13 +27,13 @@ We can actually see what that is and that's gonna be different depending on what So again, remembering that strlen is going to receive this actual memory address, so sterland takes an integer. The recurring theme that we're gonna see throughout this course is a lot of C functions actually just take integers. They just might have fancier types, but at runtime they're all integers, how does it know where the end of the strength is to calculate the length? [00:02:33] -Well, it's just gonna keep walking until it gets to a zero byte. Now we do have an error here, which is basically saying like, hey, this is an undeclared library function, been fair enough. And the solution to that is we're just going to go grab string dot h, and then we're all set so this should do exactly the same thing. +Well, it's just gonna keep walking until it gets to a zero byte. Now we do have an error here, which is basically saying like, hey, this is an undeclared library function, been fair enough. And the solution to that is we're just going to go grab string.h, and then we're all set so this should do exactly the same thing. [00:02:48] The only difference is that now it's computing the length of the string. Normally, this would be a runtime, but after optimizations, it's actually going to be done at compile time, and we won't actually have to wait for it to walk that at runtime. Okay, now that we're using strlen, we can mess this up by adding a backslash zero in here somewhere so that's essentially going to insert. [00:03:07] -We're gonna have three normal bytes, then we're gonna have a zero byte, we're gonna have a bunch of other bytes. But because write is like, give me how many bytes you want to write, now it's gonna truncate that. It's just gonna say HTTP, okay and notice that this affects not only write, but also printf, because printf is automatically doing the thing that we are now doing manually and write. +We're gonna have three normal bytes, then we're gonna have a zero byte, we're gonna have a bunch of other bytes. But because write is like, give me how many bytes you want to write, now it's gonna truncate that. It's just gonna say HTT, okay and notice that this affects not only write, but also printf, because printf is automatically doing the thing that we are now doing manually in write. [00:03:27] In other words, printf is under the hood doing that same thing, like just keep marching along the array until we hit a zero byte and then stop. So if you put a zero byte in the middle of your string, and then printf it, it's just like I guess that's where the string ends. @@ -45,7 +45,7 @@ I hit the zero, so there might be more stuff after that, you kind of intended to There are no guardrails on this stuff with C, cool. I'm gonna go ahead and just put that back, though, so we can actually see our real HTTP header. And now we're gonna change this percent S to percent ZUD, and there is gonna be a little compiler warning, but we're just gonna ignore that. [00:04:08] -And basically, what this is doing is now over here we're printing out the actual string, but in print F with the ZUD, that's saying, okay, treat this as a 64-bit integer. And it's like, yeah, I'll just print that out for you, now in this case, you might notice that when I print this out, I'm seeing slightly different numbers here. +And basically, what this is doing is now over here we're printing out the actual string, but in printf with the ZUD, that's saying, okay, treat this as a 64-bit integer. And it's like, yeah, I'll just print that out for you, now in this case, you might notice that when I print this out, I'm seeing slightly different numbers here. [00:04:24] So, they all start with four, three, something, something, something. But they do actually end up with, I guess we don't need the Z, sorry, we don't need the zud, I guess it's just zu, because there's a little D on the end there. But yeah, so this address does actually change a little bit. @@ -72,7 +72,7 @@ It's not that the binary itself is like the compiled binary is putting these in And we can, in this way, really, really confirm yeah, for real, this is a number in memory. Okay, finally, we're gonna change that back to %s and then replace the last argument, which was originally header, with this argument instead. So, there is that, so now we're getting a segmentation fault, very consistently, we're not printing anything out. [00:06:47] -So why is that happening? Well, essentially, again, this is just an integer. And if I say, basically this parenthesis is saying like, hey, I know I wrote an integer here. But just please choose to interpret this as if it were a pointer to a, it's a tar star, it's the, as if it were the address of the beginning of a string. +So why is that happening? Well, essentially, again, this is just an integer. And if I say, basically this parenthesis is saying like, hey, I know I wrote an integer here. But just please choose to interpret this as if it were a pointer to a, it's a char *, it's the, as if it were the address of the beginning of a string. [00:07:06] And I just picked the number one, two, three, four, five, six, because this is a low enough address that it's part of the operating systems reserved. You may not ever touch this memory memory, and so, because I'm basically saying, hey, let's print it, let's touch that memory. The operating system is like, absolutely not I'm shutting this down immediately segmentation fault. @@ -84,11 +84,11 @@ This is a very reliable way to segfault your program if you wanna do that. But a And now we will actually see something that is a little bit nicer, which is it actually prints out parentheses, null. So again, zero meaning null byte, as opposed to, like the actual number, null, this is something that printf just automatically does. If you give printf a zero here, well, printf obviously is like in most languages. [00:07:57] -This is where you get a null pointer exception of course he doesn't have exceptions so it's like, well you gave me a null and, I don't know what to do with that. I'm certainly not gonna like to go and try and read memory and address zero cause that's definitely gonna seg fault. +This is where you get a null pointer exception of course C doesn't have exceptions so it's like, well you gave me a null and, I don't know what to do with that. I'm certainly not gonna like to go and try and read memory at address zero cause that's definitely gonna seg fault. [00:08:09] -So, printf has special case this to be like, if you give me a zero, I'm just gonna print out parentheses null so that at least you don't have a seg fault to deal with. But it doesn't handle any other cases for you than that, as we saw earlier when I gave it 1, 2, 3, 4, 5, 6, and it happily segfaulted, so there you go. +So, printf has special cased this to be like, if you give me a zero, I'm just gonna print out parentheses null so that at least you don't have a seg fault to deal with. But it doesn't handle any other cases for you than that, as we saw earlier when I gave it 1, 2, 3, 4, 5, 6, and it happily segfaulted, so there you go. [00:08:26] -This is an example of not only printing some basic string operations, but also, I really, really wanna drive home this point that this is an integer at runtime. And so many of the things that we're gonna see and see are actually integers of memory addresses. And it's just C is deciding how to interpret those ones and zeros based on what we ask it to do. +This is an example of not only printing some basic string operations, but also, I really, really wanna drive home this point that this is an integer at runtime. And so many of the things that we're gonna see in C are actually integers of memory addresses. And it's just C is deciding how to interpret those ones and zeros based on what we ask it to do. diff --git a/en-US/2025-06-09-c-fundamentals/8-strings-memory-exercise.vtt b/en-US/2025-06-09-c-fundamentals/8-strings-memory-exercise.vtt index 14ecf858..976b28d8 100644 --- a/en-US/2025-06-09-c-fundamentals/8-strings-memory-exercise.vtt +++ b/en-US/2025-06-09-c-fundamentals/8-strings-memory-exercise.vtt @@ -38,7 +38,7 @@ here is that HTTP, 1.1 200 okay, and 9 00:00:24.733 --> 00:00:27.632 -it says that output was from right, +it says that output was from write, and this is from printf. 10 @@ -63,7 +63,7 @@ to include string.h above. 14 00:00:40.954 --> 00:00:44.310 So, this is essentially going to be like -calling right just like we did before, +calling write just like we did before, 15 00:00:44.310 --> 00:00:46.280 @@ -111,7 +111,7 @@ you wanted a string. 24 00:01:10.674 --> 00:01:14.653 So, for example, like you could put it -right after the HTTP, sorry, HTTP and +right after the HTTT, sorry, HTT in 25 00:01:14.653 --> 00:01:17.307 @@ -140,7 +140,7 @@ thing that's like, hey, 30 00:01:29.646 --> 00:01:31.271 -that output was from right, +that output was from write, this is from printf. 31 @@ -166,7 +166,7 @@ potentially. 35 00:01:45.080 --> 00:01:49.629 And then finally, try changing this back -to percent s, and then replace the printfs +to percent s, and then replace the printf's 36 00:01:49.629 --> 00:01:53.680 @@ -249,7 +249,7 @@ been fair enough. 52 00:02:41.003 --> 00:02:45.098 And the solution to that is we're just -going to go grab string dot h, and +going to go grab string.h, and 53 00:02:45.098 --> 00:02:48.593 @@ -306,7 +306,7 @@ now it's gonna truncate that. 64 00:03:18.049 --> 00:03:22.405 -It's just gonna say HTTP, okay and notice +It's just gonna say HTT, okay and notice that this affects not only write, but 65 @@ -317,7 +317,7 @@ because printf is automatically doing 66 00:03:25.130 --> 00:03:27.748 the thing that we are now -doing manually and write. +doing manually in write. 67 00:03:27.748 --> 00:03:31.073 @@ -393,7 +393,7 @@ printing out the actual string, but 82 00:04:12.800 --> 00:04:17.097 -in print F with the ZUD, that's saying, +in printf with the ZUD, that's saying, okay, treat this as a 64-bit integer. 83 @@ -642,7 +642,7 @@ this as if it were a pointer to a, 134 00:07:00.811 --> 00:07:06.942 -it's a tar star, it's the, as if it were +it's a char *, it's the, as if it were the address of the beginning of a string. 135 @@ -730,7 +730,7 @@ like in most languages. 152 00:07:57.931 --> 00:08:00.764 This is where you get a null pointer -exception of course he doesn't +exception of course C doesn't 153 00:08:00.764 --> 00:08:03.292 @@ -744,7 +744,7 @@ I don't know what to do with that. 155 00:08:04.777 --> 00:08:07.358 I'm certainly not gonna like to go and -try and read memory and +try and read memory at 156 00:08:07.358 --> 00:08:09.801 @@ -753,7 +753,7 @@ definitely gonna seg fault. 157 00:08:09.801 --> 00:08:13.219 -So, printf has special case this +So, printf has special cased this to be like, if you give me a zero, 158 @@ -789,11 +789,11 @@ point that this is an integer at runtime. 164 00:08:34.889 --> 00:08:37.073 And so many of the things -that we're gonna see and +that we're gonna see in 165 00:08:37.073 --> 00:08:39.264 -see are actually integers +C are actually integers of memory addresses. 166 diff --git a/en-US/2025-06-09-c-fundamentals/9-functions-iteration.txt b/en-US/2025-06-09-c-fundamentals/9-functions-iteration.txt index 8e24ab8e..afcaf924 100644 --- a/en-US/2025-06-09-c-fundamentals/9-functions-iteration.txt +++ b/en-US/2025-06-09-c-fundamentals/9-functions-iteration.txt @@ -8,7 +8,7 @@ So we talked previously about how we're gonna send a response back from our serv If it's a request to the /blog URL, HTTP/1.1 is just the protocol, and that's gonna have a whole bunch of headers like host and user agent and stuff like that. Basically what we're gonna do is, when we get slash blog, we're just gonna translate that into a path of a file to open. [00:00:44] -So in this case, because this one didn't end in like a file extension, it doesn't have like A in it, we're gonna assume, yeah, that's basically means they want blog slash index, dot, HTML. That's the file we're gonna look for on the file system. So also, if it ends in a slash, same thing. +So in this case, because this one didn't end in like a file extension, it doesn't have like "." in it, we're gonna assume, yeah, that's basically means they want blog/index.html. That's the file we're gonna look for on the file system. So also, if it ends in a slash, same thing. [00:00:58] We're just gonna be like, okay, that's exactly the same thing. Look for inside the blog directory index.html. So to do this, we're gonna start by just basically defining the same basic setup that we had at the end of the previous section. Except this time, instead of a response, we're gonna make a request here. @@ -20,19 +20,19 @@ And then we're gonna do some processing on it to try to extract the relevant par So we're gonna get the memory address of this beginning of the string right here, and I'm gonna use that to sort of go find the part of it that is this actual, blog. That's gona be the path Path to the thing that we want to return. And then finally, we're going to print out the path. [00:01:44] -Now, as we're going to see, this is a little bit more complicated in C than it would be in certain other languages where writing a function like two path very straightforward. Gonna be a little bit less straightforward the way we're going to do it. Okay, so the first thing is, like, in order to make a new function in C, basically, instead of returning an int, this. +Now, as we're going to see, this is a little bit more complicated in C than it would be in certain other languages where writing a function like to_path very straightforward. Gonna be a little bit less straightforward the way we're going to do it. Okay, so the first thing is, like, in order to make a new function in C, basically, instead of returning an int, this. [00:01:59] -This char star is going to sorry to path is going to return a char star. In other words, this is going to return not the exit code of the program, but rather the memory address of the actual path, once we've finished extracting the path from the request and adding the index dot HTML to the end of it. +This char star is going to sorry, this to_path is going to return a char star. In other words, this is going to return not the exit code of the program, but rather the memory address of the actual path, once we've finished extracting the path from the request and adding the index.html to the end of it. [00:02:17] -Now, in normalcy, if you do this, like if you You just write this code exactly as is, you're giving it an error that says, hey, you're trying to call this function called to path before it was defined. What's up with that? So C basically has two ways you can address this. +Now, in normal C, if you do this, like if you You just write this code exactly as is, you're gonna get an error that says, hey, you're trying to call this function called to_path before it was defined. What's up with that? So C basically has two ways you can address this. [00:02:31] -One is you can say, I want to forward declare it, which is basically where you write out just the type of the function with a semicolon at the end, above where you're actually going to call it. And this sort of lets see, know, as it's like coming through and processing everything. +One is you can say, I want to forward declare it, which is basically where you write out just the type of the function with a semicolon at the end, above where you're actually going to call it. And this sort of lets C know, as it's like coming through and processing everything. [00:02:43] -It says, okay, there is a function by this name. Here's the type. I see what it is. Great. When I'm calling it, I know what its type is, even though it hasn't been defined in terms of its implementation yet. And then later on, you can do it like that, or you can just simplify things and just move the function up and define it before me and. +It says, okay, there is a function by this name. Here's the type. I see what it is. Great. When I'm calling it, I know what its type is, even though it hasn't been defined in terms of its implementation yet. And then later on, you can do it like that, or you can just simplify things and just move the function up and define it before main. [00:03:00] Again, this is one of those 1972 ergonomics kind of things. So as an example of the type of string we might pass in here, we might say input is, do a string, get slash, blog, HTTP, 1.1 and what we want to end up with is get rid of this initial thing, which is the method, which will be like your get, put post, delete one of those. @@ -44,7 +44,7 @@ Get rid of that thing. Also get rid of the leading slash here. And then add slas In other words, this address is going to be the same as this address. And what we want to do is we want to move from that start address, which is the very beginning of the string, and we want to just advance it until we get to right here. [00:03:50] -Because this is the point where we're at the end of this, like, G, E, T, and we're like, yeah, we're done parsing that. So this thing could be a get, it could be a post. It could be a put. We want to find this space. Phase because that let us know that we've moved past http verb and we can now actually get to the thing we care about which is the path. +Because this is the point where we're at the end of this, like, G, E, T, and we're like, yeah, we're done parsing that. So this thing could be a get, it could be a post. It could be a put. We want to find this space because that lets us know that we've moved past the http verb and we can now actually get to the thing we care about which is the path. [00:04:07] So let's just write the logic to sort of advance this start thing over from this initial address to there. Well, to do this, basically, we can just write a while loop. So we say, while (start[0] and start back at 0 essentially means We're treating this memory address as essentially an array. @@ -53,7 +53,7 @@ So let's just write the logic to sort of advance this start thing over from this Bracket zero means, you know, get me the first element of that array. So essentially what this is saying is take what's at this memory address, give me the byte that's right at this exact memory address, and keep looping until we hit a space at which point the loop will end. [00:04:37] -And then at the end of the loop, we're gonna do start equals start plus one. Don't worry, we will change this to a for loop later, [LAUGH] But for now we're just gonna do it wild style. And basically this is a way of saying, okay, I want to just move this address up one. +And then at the end of the loop, we're gonna do start equals start plus one. Don't worry, we will change this to a for loop later, [LAUGH] But for now we're just gonna do it while style. And basically this is a way of saying, okay, I want to just move this address up one. [00:04:50] I'm just gonna take this actual integer, because again, this is a memory address, and just increment it. Just move one slot at a time. And as we're doing this, we're going to effectively be going one character at a time Until eventually we end up with the character being space. @@ -95,19 +95,19 @@ So null address basically just means. Memory addresses are integers and memory. By the way, C does allow you to write it exactly like this, so you might notice I did not put curly braces here. Those curly braces are optional in c If you want, you can write an if and then no curly braces right after it. And it will just take the next statement that you have and say, that only applies to this conditional. [00:08:10] -And then the thing after it applies to something else. Now, a problem with this is that it's very easy to make the mistake especi. Especially because code formatters like prettier and stuff, are not actually that common in the c world. What if you indent like this and you look at this code and you're like, yeah, that's all part of the conditional, but it's not because there's no curly braces there. +And then the thing after it applies to something else. Now, a problem with this is that it's very easy to make the mistake especi. Especially because code formatters like prettier and stuff, are not actually that common in the C world. What if you indent like this and you look at this code and you're like, yeah, that's all part of the conditional, but it's not because there's no curly braces there. [00:08:30] So, this actually was the cause of a pretty famous bug called Hardbleed, basically what happened was, they traced it back and tried to figure out how this, Bug, which turned out to be a very serious exploit happened, and it actually came down to this, where someone had written an if without curly braces, but indented like this. [00:08:47] -And it looked like these were both part of the conditional, but actually only the first one was part of the conditional. And that was the source of the book. So the moral of the story is always put curly braces around your conditional. This is not worth saving the extra characters. +And it looked like these were both part of the conditional, but actually only the first one was part of the conditional. And that was the source of the bug. So the moral of the story is always put curly braces around your conditional. This is not worth saving the extra characters. [00:08:59] So we're going to put those in there, even though C doesn't require you to. I mentioned this mainly so that if you see in the while the C code that's doesn't have the curly braces there, you understand that like they're not required. But as a matter of good practice, I would always recommend putting them in. [00:09:12] -Okay, now I mentioned earlier that we can convert this while loop to a for loop, and that's, this is what that looks like. So for loops essentially have three in green. So the first one is basically the initialization condition. So this is what's gonna run at the very beginning of the for loop. +Okay, now I mentioned earlier that we can convert this while loop to a for loop, and that's, this is what that looks like. So for loops essentially have three ingredients. So the first one is basically the initialization condition. So this is what's gonna run at the very beginning of the for loop. [00:09:26] So we're basically saying, okay, I'm to take a start and initialize it to be equal to rec. So this is the same exact thing that we were doing here in the while loop outside the loop. You can just do that as part of the for loop. And you can also, if you want, move the char star. @@ -116,34 +116,34 @@ So we're basically saying, okay, I'm to take a start and initialize it to be equ Inside of there. And then basically what this will do is this will say that if I put it in here as opposed to out here, it's basically saying that start is only going to be in scope inside this loop. And if anybody outside the loop tries to reference it, that it's gonna give a compiler. [00:09:54] -And then basically we have the same condition in here, like keep going until it. It hits the space. And then this is what we do on each iteration of the loop once we get to the end. So this thing right here, just des sugars to exactly the same thing we had in the wild loop. +And then basically we have the same condition in here, like keep going until it. It hits the space. And then this is what we do on each iteration of the loop once we get to the end. So this thing right here, just desugars to exactly the same thing we had in the while loop. [00:10:07] Same logic, just a different way to write it. C doesn't have a concept for each loop or any other fancier for syntax than this. It's really just like initialization the condition to check at the end of each. Iteration of the loop and or, sorry, at the beginning of each iteration of the loop, and then the operation to run at the end of each iteration of the loop. [00:10:27] -Okay, all right, so we started off with our start thing, which we actually are going to keep outside of the loop, so that we can have it in scope later on. Because the next thing we want to do after we. To get to right here is we want to say, well, let's throw that space away. +Okay, all right, so we started off with our start thing, which we actually are going to keep outside of the loop, so that we can have it in scope later on. Because the next thing we want to do after we increment start to get to right here is we want to say, well, let's throw that space away. [00:10:44] Let's just advance past it. So having start be explicitly outside the loop means that we can then just do start plus plus to say, okay, we found the space, the loop exited, and now we're just going to skip over that space. So now if we print out start right here, what it's going to print is again, Again, because start is a memory address. [00:11:01] -It's gonna say, okay, well that memory address is right here. So, if we literally say printf start, and then present S start, what's gonna get printed out to the screen is start and then slash blog [INAUDIBLE]. So it's this memory address. And then print out everything until we hit the, the null Terminator Now, what we have right here is our goal, sorry, our input is a GET and all that. +It's gonna say, okay, well that memory address is right here. So, if we literally say printf start, and then %s, start, what's gonna get printed out to the screen is start and then /blog HTTP blah, blah. So it's this memory address. And then print out everything until we hit the, the null Terminator Now, what we have right here is our goal, sorry, our input is a GET and all that. [00:11:27] Let's say that we wanted to end up with a goal of that. What we could just say, look, just overwrite it to 0. Just take this as the input and just boom, just set it to the null terminator. And now when you print it out, it's gonna be, yeah, Okay, no problem. [00:11:40] -There's, an alternator. Like we encountered it. We're not gonna print out anything. But that's not actually our goal, right? What we actually wanna do is we wanna end up with this thing right here. So let's go ahead and continue doing that right here in place. So now we're gonna do another for loop, where this time we are, starting off with, end equals start. +There's a null terminator, like, we encountered it. We're not gonna print out anything. But that's not actually our goal, right? What we actually wanna do is we wanna end up with this thing right here. So let's go ahead and continue doing that right here in place. So now we're gonna do another for loop, where this time we are, starting off with, end equals start. [00:11:59] So we've defined an additional variable up here called end. This is gonna be another memory address. And now what we're trying to do is we're trying to find out okay. If this is the start of this thing where is the end. So the end is going to be basically where this other space happens because these are space separated. [00:12:14] -So right now we're just trying to isolate this slash blog right in here. Okay so at first, what we're gonna do that is we're gonna, so I'm basically saying, like, okay, do exactly the same logic in here that we did before, where, we initialize end to be start, and then we just keep going until we hit a space. +So right now we're just trying to isolate this /blog right in here. Okay so at first, what we're gonna do that is we're gonna, so I'm basically saying, like, okay, do exactly the same logic in here that we did before, where, we initialize end to be start, and then we just keep going until we hit a space. [00:12:32] -So these two loops are gonna be identical. Just keep going until you hit a space, with the added, like, a little edge case of, and by the way, if along the way. We happen to encounter a null bite, then just early return from the entire function. So that's what both of these are doing. +So these two loops are gonna be identical. Just keep going until you hit a space, with the added, like, a little edge case of, and by the way, if along the way. We happen to encounter a null byte, then just early return from the entire function. So that's what both of these are doing. [00:12:46] So this will end up with end being initialized to this space right here. So we had start, which found the first space going through the loop. We did start plus plus to get to the slash and then now we have gone through the loop to get end. Being right here where the other space is. @@ -155,22 +155,22 @@ Now at this point, we're gonna say, okay, I wanna ensure that there is a slash h What we can do here is we can say end bracket negative one. And what this means is. Take this memory address, subtract one element from it. So subtract one byte from it. So in other words, if end is right here, we're going to subtract one and get to that G right there, and basically say, if that is a slash. [00:13:31] -In other words, if it was a get of slash, blog slash, then in that case, we're going to subtract one from end. So this is basically a way of handling in a, very see, like way the edge case, where? Okay, well, what if we got slash blog with a slash at the end. +In other words, if it was a GET of /blog/, then in that case, we're going to subtract one from end. So this is basically a way of handling in a, very C like way the edge case, where? Okay, well, what if we got slash blog with a slash at the end. [00:13:45] -So / blog / and / blog, we want to treat those the same way. This is this does that it basically says we've ended up with end being at this, the address of the space right here, if there is a slash of that space right there, then we're just going to move it back one, so that it ends up being Them right there. +So / blog / and / blog, we want to treat those the same way. This is this does that it basically says we've ended up with end being at this, the address of the space right here, if there is a slash of that space right there, then we're just going to move it back one, so that it ends up being right there. [00:14:02] And then basically we say, okay, cool, if there was a space there, then just move back one, and otherwise we're actually going to write a slash in there. So now what we've done is we've essentially said, okay, cool, either there was a slash there and a space after it, in which case we moved back to use the slash that was already there, or if there wasn't a slash there, we're going to write one there. [00:14:20] -Now note that this right here, this end[0]=, this is actually mutating the original request string. So we were passed in this request and you might look at this function signature and say like, two path takes a request, and then it returns the path from it. Therefore, obviously we're not gonna touch that request. +Now note that this right here, this end[0]=, this is actually mutating the original request string. So we were passed in this request and you might look at this function signature and say like, to_path takes a request, and then it returns the path from it. Therefore, obviously we're not gonna touch that request. [00:14:39] -We're just gonna look at it and we're gonna make a nice new And we're going to return the new path. Well, we could do that, but this is C. And actually the way that we're doing it here is the most efficient way to do it. If we wanted to make an entirely new string and then return it from the function, we're going to see how to do that later, but it would be actually significantly less efficient than if we just said, yeah, you know what? +We're just gonna look at it and we're gonna make a nice new path and we're going to return the new path. Well, we could do that, but this is C. And actually the way that we're doing it here is the most efficient way to do it. If we wanted to make an entirely new string and then return it from the function, we're going to see how to do that later, but it would be actually significantly less efficient than if we just said, yeah, you know what? [00:14:58] -This request, this is my memory, it's fair game. I can write to it if I want to, To, I can mutate it in place if I want to, and I do want to, I'm going to do it that way. So we're going to start by just looking at how to do it in the most efficient way, where we are actually mutating the bytes of the original string that we were passed in in order to get the path that we want to return. +This request, this is my memory, it's fair game. I can write to it if I want to, I can mutate it in place if I want to, and I do want to, I'm going to do it that way. So we're going to start by just looking at how to do it in the most efficient way, where we are actually mutating the bytes of the original string that we were passed in in order to get the path that we want to return. [00:15:17] So essentially, what we're doing right here is we're saying, Okay, if we didn't already have a slash there for. From the original request now that we're going to put one right there. So we're essentially writing this slash right in here. And now, basically we've ended up with regardless of whether or not there was a slash there at the beginning, there is a slash there now. diff --git a/en-US/2025-06-09-c-fundamentals/9-functions-iteration.vtt b/en-US/2025-06-09-c-fundamentals/9-functions-iteration.vtt index 5985143c..d4ecc7e6 100644 --- a/en-US/2025-06-09-c-fundamentals/9-functions-iteration.vtt +++ b/en-US/2025-06-09-c-fundamentals/9-functions-iteration.vtt @@ -82,13 +82,13 @@ didn't end in like a file extension, 18 00:00:47.928 --> 00:00:50.436 -it doesn't have like A in it, +it doesn't have like "." in it, we're gonna assume, yeah, 19 00:00:50.436 --> 00:00:53.271 that's basically means they want -blog slash index, dot, HTML. +blog/index.html. 20 00:00:53.271 --> 00:00:56.397 @@ -185,7 +185,7 @@ in C than it would be in certain other 39 00:01:48.717 --> 00:01:52.023 languages where writing a function -like two path very straightforward. +like to_path very straightforward. 40 00:01:52.023 --> 00:01:55.141 @@ -204,8 +204,8 @@ this. 43 00:01:59.864 --> 00:02:04.206 -This char star is going to sorry to -path is going to return a char star. +This char star is going to sorry, this +to_path is going to return a char star. 44 00:02:04.206 --> 00:02:08.714 @@ -220,22 +220,22 @@ path, once we've finished extracting 46 00:02:13.436 --> 00:02:17.604 the path from the request and adding -the index dot HTML to the end of it. +the index.html to the end of it. 47 00:02:17.604 --> 00:02:21.403 -Now, in normalcy, if you do this, like +Now, in normal C, if you do this, like if you You just write this code exactly 48 00:02:21.403 --> 00:02:23.878 as is, -you're giving it an error that says, hey, +you're gonna get an error that says, hey, 49 00:02:23.878 --> 00:02:27.523 you're trying to call this function -called to path before it was defined. +called to_path before it was defined. 50 00:02:27.523 --> 00:02:28.906 @@ -263,7 +263,7 @@ actually going to call it. 55 00:02:40.481 --> 00:02:42.663 -And this sort of lets see, know, +And this sort of lets C know, as it's like coming through and 56 @@ -305,7 +305,7 @@ that, or you can just simplify things and 64 00:02:57.488 --> 00:03:00.350 just move the function up and -define it before me and. +define it before main. 65 00:03:00.350 --> 00:03:03.261 @@ -409,12 +409,12 @@ It could be a put. 86 00:03:59.311 --> 00:03:59.992 -We want to find this space. +We want to find this space 87 00:03:59.992 --> 00:04:03.882 -Phase because that let us know that -we've moved past http verb and +because that lets us know that +we've moved past the http verb and 88 00:04:03.882 --> 00:04:07.854 @@ -477,7 +477,7 @@ loop later, [LAUGH] But for 100 00:04:43.716 --> 00:04:45.518 -now we're just gonna do it wild style. +now we're just gonna do it while style. 101 00:04:45.518 --> 00:04:48.238 @@ -830,7 +830,7 @@ like prettier and stuff, 176 00:08:21.765 --> 00:08:24.151 are not actually that -common in the c world. +common in the C world. 177 00:08:24.151 --> 00:08:27.608 @@ -878,7 +878,7 @@ was part of the conditional. 186 00:08:52.689 --> 00:08:54.351 -And that was the source of the book. +And that was the source of the bug. 187 00:08:54.351 --> 00:08:57.037 @@ -922,7 +922,7 @@ that's, this is what that looks like. 195 00:09:17.937 --> 00:09:20.017 So for -loops essentially have three in green. +loops essentially have three ingredients. 196 00:09:20.017 --> 00:09:24.319 @@ -1017,8 +1017,8 @@ So this thing right here, 216 00:10:04.680 --> 00:10:07.877 -just des sugars to exactly the same -thing we had in the wild loop. +just desugars to exactly the same +thing we had in the while loop. 217 00:10:07.877 --> 00:10:09.824 @@ -1058,11 +1058,11 @@ that we can have it in scope later on. 224 00:10:36.952 --> 00:10:41.177 Because the next thing -we want to do after we. +we want to do after we increment start 225 00:10:41.177 --> 00:10:44.364 -To get to right here is we want to say, +to get to right here is we want to say, well, let's throw that space away. 226 @@ -1101,12 +1101,12 @@ well that memory address is right here. 233 00:11:05.337 --> 00:11:08.858 So, if we literally say printf start, -and then present S start, +and then %s, start, 234 00:11:08.858 --> 00:11:13.351 what's gonna get printed out to the screen -is start and then slash blog [INAUDIBLE]. +is start and then /blog HTTP blah, blah. 235 00:11:13.351 --> 00:11:15.557 @@ -1144,11 +1144,11 @@ it's gonna be, yeah, Okay, no problem. 242 00:11:40.699 --> 00:11:41.666 -There's, an alternator. +There's a null terminator, 243 00:11:41.666 --> 00:11:42.345 -Like we encountered it. +like, we encountered it. 244 00:11:42.345 --> 00:11:43.825 @@ -1208,7 +1208,7 @@ are space separated. 256 00:12:14.941 --> 00:12:20.240 So right now we're just trying to -isolate this slash blog right in here. +isolate this /blog right in here. 257 00:12:20.240 --> 00:12:24.587 @@ -1241,7 +1241,7 @@ by the way, if along the way. 263 00:12:39.889 --> 00:12:41.904 -We happen to encounter a null bite, +We happen to encounter a null byte, 264 00:12:41.904 --> 00:12:44.736 @@ -1325,8 +1325,8 @@ basically say, if that is a slash. 281 00:13:31.559 --> 00:13:35.288 -In other words, if it was a get of slash, -blog slash, then in that case, +In other words, if it was a GET +/blog/, then in that case, 282 00:13:35.288 --> 00:13:37.324 @@ -1335,7 +1335,7 @@ we're going to subtract one from end. 283 00:13:37.324 --> 00:13:40.865 So this is basically a way -of handling in a, very see, +of handling in a, very C 284 00:13:40.865 --> 00:13:43.005 @@ -1368,7 +1368,7 @@ that space right there, 290 00:13:57.705 --> 00:14:02.213 then we're just going to move it back one, -so that it ends up being Them right there. +so that it ends up being right there. 291 00:14:02.213 --> 00:14:06.487 @@ -1417,7 +1417,7 @@ might look at this function signature and 300 00:14:32.515 --> 00:14:36.725 -say like, two path takes a request, +say like, to_path takes a request, and then it returns the path from it. 301 @@ -1428,7 +1428,7 @@ not gonna touch that request. 302 00:14:39.361 --> 00:14:41.679 We're just gonna look at it and -we're gonna make a nice new And +we're gonna make a nice new path and 303 00:14:41.679 --> 00:14:43.075 @@ -1465,7 +1465,7 @@ it's fair game. 310 00:15:01.205 --> 00:15:04.438 -I can write to it if I want to, To, +I can write to it if I want to, I can mutate it in place if I want to, and 311