You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Copy file name to clipboardExpand all lines: Embedded_C/C_Language_Fundamentals.md
+151Lines changed: 151 additions & 0 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -165,6 +165,22 @@ C Memory Layout:
165
165
166
166
### **Compilation Process**
167
167
168
+
C on embedded targets compiles into multiple object files (translation units) that the linker places into memory regions defined by a linker script. Understanding this flow helps you read the map file and control where data/code lands.
169
+
170
+
### Concept: Translation units, linkage, and the linker script
171
+
- A source + its headers → a translation unit → one object file.
172
+
- The linker merges objects and libraries, resolving external symbols.
173
+
- The linker script maps sections (\`.text\`, \`.rodata\`, \`.data\`, \`.bss\`) into Flash/RAM.
174
+
175
+
### Try it
176
+
1. Build with `-Wl,-Map=out.map` and open the map file. Locate a `static const` table vs a non-const global.
177
+
2. Change a symbol from `static` to non-`static` and observe its visibility (external vs internal linkage).
178
+
179
+
### Takeaways
180
+
- The map file is your truth for footprint and placement.
181
+
-`static` at file scope gives internal linkage; keep symbols local by default.
182
+
- Use sections/attributes only when you must control placement; prefer defaults first.
183
+
168
184
C programs go through several stages before execution:
169
185
170
186
```
@@ -200,6 +216,39 @@ C uses a **static type system** with **weak typing**:
200
216
201
217
## 🔢 **Variables and Data Types**
202
218
219
+
### Concept: Where does the object live and when does it die?
220
+
221
+
Rather than memorizing types, think in terms of storage duration and lifetime: who owns the object, where is it placed in memory, and when is it initialized/destroyed. On MCUs, these choices affect RAM usage, startup cost, determinism, and safety.
222
+
223
+
### Why it matters in embedded
224
+
- Static objects may be zero‑initialized by the startup code and can live in Flash (if `const`), reducing RAM.
225
+
- Automatic (stack) objects are fast and deterministic to allocate but are uninitialized by default.
226
+
- Dynamic (heap) objects increase flexibility but can hurt predictability and fragment memory.
227
+
228
+
### Minimal example
229
+
```c
230
+
int g1; // Zero-initialized (\`.bss\`)
231
+
staticint g2 = 42; // Pre-initialized (\`.data\`)
232
+
233
+
voidf(void) {
234
+
int a; // Uninitialized (stack, indeterminate)
235
+
static int b; // Zero-initialized, retains value across calls
236
+
static const int lut[] = {1,2,3}; // Often placed in Flash/ROM
237
+
(void)a; (void)b; (void)lut;
238
+
}
239
+
```
240
+
241
+
### Try it
242
+
1. Print addresses of `g1`, `g2`, a local variable, and `b`. Inspect the linker map to see section placement (\`.text\`, \`.data\`, \`.bss\`, stack).
243
+
2. Make `lut` large and observe Flash vs RAM usage in the map file when `const` is present vs removed.
244
+
245
+
### Takeaways
246
+
- Only static storage duration is guaranteed zero‑init. Stack locals are indeterminate until assigned.
247
+
- `static` inside a function behaves like a global with function scope.
248
+
- `const` data may reside in non‑volatile memory; don’t cast away `const` to write to it.
249
+
250
+
> Platform note: On Cortex‑M, large zero‑initialized objects increase \`.bss\` and extend startup clear time; large initialized objects increase \`.data\` copy time from Flash to RAM.
251
+
203
252
### **What are Variables?**
204
253
205
254
Variables are named storage locations in memory that can hold data. In C, variables must be declared before use, specifying their type and optionally initializing them with a value.
@@ -300,6 +349,39 @@ typedef enum {
300
349
301
350
## 🔧 **Functions**
302
351
352
+
### Concept: Keep work small, pure when possible, and observable
353
+
354
+
In embedded, function design drives predictability and testability. Prefer small, single-purpose functions with explicit inputs/outputs. Avoid hidden dependencies (globals) except for well-defined hardware interfaces behind an abstraction.
355
+
356
+
### Why it matters in embedded
357
+
- Smaller functions improve stack usage estimation and inlining opportunities.
358
+
- Pure functions are easier to unit test off-target.
359
+
- Explicit interfaces reduce coupling to hardware and timing.
### Concept: Prefer early returns and shallow nesting
469
+
470
+
Deeply nested branches increase cyclomatic complexity and code size on MCUs. Early returns with guard clauses keep critical paths obvious and reduce stack pressure in error paths.
471
+
472
+
### Minimal example
473
+
```c
474
+
// Nested
475
+
bool handle_packet(const pkt_t* p) {
476
+
if (p) {
477
+
if (valid_crc(p)) {
478
+
if (!seq_replay(p)) { process(p); return true; }
479
+
}
480
+
}
481
+
return false;
482
+
}
483
+
484
+
// Guarded
485
+
bool handle_packet(const pkt_t* p) {
486
+
if (!p) return false;
487
+
if (!valid_crc(p)) return false;
488
+
if (seq_replay(p)) return false;
489
+
process(p);
490
+
return true;
491
+
}
492
+
```
493
+
494
+
### Takeaways
495
+
- Shallow nesting improves readability and timing analysis.
496
+
- Use switch for dense dispatch; avoid fall-through unless deliberate and documented.
497
+
- In ISR-adjacent code, keep branches short and avoid loops without clear bounds.
498
+
386
499
### **What are Control Structures?**
387
500
388
501
Control structures determine the flow of program execution. They allow programs to make decisions, repeat operations, and organize code execution.
### Mental model: Arrays are blocks; pointers are addresses with intent
763
+
764
+
An array name in an expression decays to a pointer to its first element. The array itself has a fixed size and lives where it was defined (stack, \`.bss\`, \`.data\`). A pointer is just an address that can point anywhere and can be reseated.
765
+
766
+
### Why it matters in embedded
767
+
- Knowing when decay happens prevents bugs with `sizeof` and parameter passing.
768
+
- Arrays placed in Flash as `static const` look like ordinary arrays but are read‑only and may require `volatile` when mapped to hardware.
769
+
770
+
### Minimal example: decay and sizeof
771
+
```c
772
+
staticuint8_t table[16];
773
+
774
+
size_t size_in_caller = sizeof table; // 16
775
+
776
+
voiduse_array(uint8_t *p) {
777
+
size_t size_in_callee = sizeof p; // size of pointer, not array
778
+
(void)size_in_callee;
779
+
}
780
+
781
+
void demo(void) {
782
+
use_array(table); // array decays to uint8_t*
783
+
}
784
+
```
785
+
786
+
### Try it
787
+
1. Print `sizeof table` in the defining scope and inside a callee parameter.
788
+
2. Change the parameter to `uint8_t a[16]` and observe it’s still a pointer in the callee.
789
+
3. Create `static const uint16_t lut[] = { ... }` and verify via the map file whether it resides in Flash/ROM.
790
+
791
+
### Takeaways
792
+
- Arrays are not pointers; they decay to pointers at most expression boundaries.
793
+
- `sizeof(param)` inside a function where `param` is declared as `type param[]` yields the pointer size.
794
+
- Prefer passing `(ptr, length)` pairs, or wrap in a `struct` to preserve size information.
795
+
796
+
> Cross‑links: See `Type_Qualifiers.md` for `const/volatile` on memory‑mapped regions, and `Structure_Alignment.md` for layout implications.
797
+
649
798
### **What are Arrays?**
650
799
651
800
Arrays are collections of elements of the same type stored in contiguous memory locations. They provide efficient access to multiple related data items.
@@ -813,6 +962,8 @@ typedef union {
813
962
814
963
## 🔧 **Preprocessor Directives**
815
964
965
+
> Guideline: Keep macros minimal and local. Prefer `static inline` functions for type safety, debuggability, and better compiler analysis unless you truly need token pasting/stringification or compile‑time branching.
966
+
816
967
### **What are Preprocessor Directives?**
817
968
818
969
Preprocessor directives are instructions to the C preprocessor that are processed before compilation. They provide text substitution, conditional compilation, and file inclusion capabilities.
0 commit comments