switch to C

This commit is contained in:
anihilis 2025-12-21 10:31:31 -08:00
parent b081820659
commit bf5837389a
3 changed files with 551 additions and 0 deletions

284
qfetchC-notes.txt Normal file
View file

@ -0,0 +1,284 @@
Perfect — lets switch hats from *“just making it work”* to *“learning C properly”*.
Ill explain **how to read and think about this file**, not just what it does.
Ill reference the structure you now have in the file and explain the *C concepts* behind each part.
---
## 1⃣ The mindset shift: C vs C++
In C:
* ❌ No classes, no RAII, no `std::string`
* ✅ **You control memory explicitly**
* ✅ Functions are small, focused, and composable
* ✅ Portability comes from *conditional compilation*
Your program follows a **very idiomatic C pattern**:
> *“Each function returns ownership of dynamically allocated data, and the caller frees it.”*
Thats a **huge** C concept to internalize.
---
## 2⃣ Feature macros (`_POSIX_C_SOURCE`)
```c
#define _POSIX_C_SOURCE 200809L
```
### Why this exists
C standard libraries hide some functions unless you *opt in*.
This line tells the compiler:
> “I want modern POSIX features like `strdup`, `gethostname`, `sysconf`.”
Without it:
* Some systems wont expose those functions
* Youll get mysterious warnings or missing symbols
**Lesson:**
👉 In C, *what functions exist* depends on feature macros.
---
## 3⃣ Headers: what C teaches you here
```c
#include <stdio.h> // printf, FILE
#include <stdlib.h> // malloc, free
#include <string.h> // strlen, strdup
#include <unistd.h> // POSIX functions
```
In C:
* Headers are **contracts**
* If its not included, the compiler assumes *nothing*
**Rule of thumb:**
> If you call a function, its header must be included — no exceptions.
---
## 4⃣ Conditional compilation (`#if defined(...)`)
Example:
```c
#if defined(__APPLE__) || defined(__FreeBSD__)
#include <sys/sysctl.h>
#endif
```
### What this teaches you
* C has **no runtime reflection**
* Portability happens at **compile time**
* The preprocessor literally removes code before compilation
Think of it as:
```text
“Only compile this code if the OS supports it.”
```
This is how *real* portable C software works (git, curl, openssh).
---
## 5⃣ The most important function in the file
```c
static char *dup_or_unknown(const char *s)
```
### Why this exists
This function enforces a **contract**:
* Every getter:
* returns a valid `char *`
* never returns `NULL`
* always returns heap memory
### Why that matters
It lets `main()` be *simple*:
```c
char *user = get_user();
/* ... */
free(user);
```
No special cases.
No defensive `if (ptr)` checks.
**Lesson:**
👉 In C, helper functions enforce invariants so callers stay clean.
---
## 6⃣ Dynamic allocation patterns (CRITICAL)
Example:
```c
char *buf = malloc(len);
snprintf(buf, len, "...", ...);
return buf;
```
### This is idiomatic C
Rules being followed:
1. Allocate **exactly what you need**
2. Initialize before use
3. Return ownership to the caller
4. Caller must `free()`
Contrast this with C++:
* No destructors
* No smart pointers
* No safety net
**Lesson:**
👉 In C, *ownership is a social contract*, not a language feature.
---
## 7⃣ Why no global buffers?
You *could* have done:
```c
static char buf[256];
```
But that would:
* Break thread safety
* Break reentrancy
* Make functions non-composable
Dynamic allocation makes your functions:
* Reusable
* Testable
* Library-quality
**Lesson:**
👉 Globals are easy — dynamic ownership is correct.
---
## 8⃣ Reading system information in C
Each platform teaches a lesson:
### Linux
```c
/proc/cpuinfo
/proc/uptime
```
* Text parsing
* Line-by-line scanning
* Defensive string handling
### macOS / BSD
```c
sysctl()
```
* Structured kernel APIs
* Buffer-size negotiation
* Integer & struct-based data
**Lesson:**
👉 C doesnt abstract the OS — it exposes it.
---
## 9⃣ Time handling (classic C pain point)
```c
time_t now = time(NULL);
difftime(now, boottime.tv_sec);
```
Why this matters:
* `time_t` may not be an integer
* You *never* subtract times directly
* `difftime()` handles portability
**Lesson:**
👉 In C, use the standard library *exactly as intended*.
---
## 🔟 The `main()` function: clean by design
```c
char *user = get_user();
/* ... */
free(user);
```
Notice:
* No logic
* No parsing
* No platform checks
* No error handling clutter
All complexity lives *outside* `main()`.
**Lesson:**
👉 In C, `main()` should read like a script.
---
## 1⃣1⃣ What this code teaches you overall
Youve learned:
* ✅ How C handles memory *explicitly*
* ✅ How portability really works
* ✅ How to design safe APIs in unsafe languages
* ✅ How Unix exposes system information
* ✅ How real-world C programs are structured
This is **not beginner C** — this is *professional-grade foundational C*.
---
## If you want to go deeper next
From a learning perspective, great next steps would be:
* 🔹 Splitting into `.h` / `.c`
* 🔹 Writing your own `string_builder`
* 🔹 Adding error-return variants (`int get_x(char **out)`)
* 🔹 Making this a reusable library
* 🔹 Running it under `valgrind` and analyzing output
If you want, I can:
* Rewrite one function *line by line* explaining *every character*
* Or turn this into a **guided C learning project**
Just tell me how deep you want to go — youre asking exactly the right questions 👏