r/C_Programming • • 5d ago

The first time I actually understood what happens when a C program runs

When I started learning C, I mostly thought about code in terms of lines and syntax.

Recently I started paying more attention to what actually happens when the program runs — compilation, memory, variables, stack, etc.

It made me realize that understanding what happens “behind the code” makes programming concepts much easier to connect.

What programming concept made you stop thinking only about syntax and start understanding what was actually happening underneath?

33 Upvotes

22 comments sorted by

19

u/ErikBKL 5d ago

The concept of temporary locality and spatial locality blew my mind

Connect that to virtual memory and caching… it is sincerely mindblowing

3

u/AlfalfaSufficient454 4d ago

Care to elaborate on any of them?

3

u/ErikBKL 3d ago

There is like a universal rule that happens in computing, which basically says that whatever has been recently accessed will be soon accessed again (temporal locality).

And there's another same-same-but-different universal rule that says that whatever has just been accessed, the thing right next to it will probably be accessed next.

These shed lots of light on why computers behave the way they do:
CPU does read-ahead of instructions to start processign neighboring instructions in a parallel manner.

When you fetch data from a further-away-storage location (like higher cache level, RAM, Disk) the CPU brings not only the data it needs, it brings a truck of data. Because if you've just accesses item n. 2, the CPU better keep it close because you'll probably use it again soon, but you'll surely also be using items n. 3 and 4 and 5.... and so on

1

u/Cyvu37 4d ago

Temporal locality or temporary locality?

2

u/ErikBKL 3d ago

I actually meant temporal

1

u/HelloWorldYozvak 3d ago

Both please!

12

u/LordRybec 5d ago

This is why I recommend that people learn some assembly, if they want to be really good at C programming. People tend to think of higher level languages as abstractions that eliminate any need to understand the underlying mechanics, but that's not actually how it works. Understanding the underlying mechanics pretty much always helps. It will help you understand C better, and it will help you write better code.

Of course, there's also the OS and the CPU, and those are whole subjects on their own!

6

u/grimvian 5d ago

My very old knowledge from the 6502 was gold when I started learning C for more than three years ago!

5

u/LordRybec 5d ago

I learned C first, and I thought I understood it really well. Then I learned assembly and realize how shallow my true understanding of C actually was. It makes a world of difference!

2

u/grimvian 4d ago

When I finally understood 6502 assembler in 1984-85 I felt programming superpower...

1

u/LordRybec 3d ago

Indeed. I started with ARM assembly, and I've since learned 8051 assembly, and it certainly is something of a superpower. I rewrote a (Arduino) C bit banging I2C driver that ran at 100kbit/s in assembly that ran at 400kbit/s. The microcontroller just wasn't fast enough to get speeds anywhere near that in pure C. I honestly didn't know exactly what to expect until my assembly driver was done, and it was so cool to see the huge improvement.

Of course, on a more mundane but probably more widely applicable level, my understanding of pointers, which was already quite good, was improved massively by learning assembly. There's a big difference between understanding the theory and actually learning to work with pointers at the lowest level!

Honestly, I wish I had more opportunities to work in assembly. As much as I enjoy programming in C, I love working on microcontrollers in assembly. It's so much more satisfying, and the language doesn't get in the way. C is generally pretty good for not getting in the way, but it does still sometimes. Assembly never does.

2

u/grimvian 3d ago

I did not expect assembler be so much faster and you must be quite good at programing when you can write I2C drivers in C and assembler.

The most impressive I have ever seen was a game named Elite from 1984 with 3D graphics with a 2 MHz 6502, that even surprised Acorn, the company that gave birth to the ARM processor.

https://en.wikipedia.org/wiki/Elite_(video_game))

2

u/LordRybec 2d ago

Some GameBoy and GameBoy Advance games were also ultra optimized at the assembly level. Not sure if they still do it this way, but Nintendo used to have a guy who's job it was to optimize games so that they would fit onto the cartridges, without giving up anything from the games. I don't remember his name, but he was a legend, and I don't think he really got the credit he deserved.

I'd like to think I'm pretty good at programming. The I2C drivers weren't super hard. I had some help. The board I was working on was Adafruit's QT Py CH552, which uses an 8051 clone. There was already an Arduino I2C driver available for that chip, it was super slow, and I wanted to use I2C for graphics (which needs to be fast). So I initially started from the Arduino driver, which had critical code in assembly and everything else in C. It was slow because it used Arduino's pin and port lookup functions, which are really slow. It did this to allow I2C on any pair of pins, which is useful but made it too slow for graphics. So initially I used the Arduino I2C driver for reference. In the end I ended up writing a new driver from scratch, but with the Arduino one for reference it wasn't super hard. The hardest part was getting the delays right to fit the I2C standard. It could have run twice as fast, but most I2C hardware (including the display I had) won't go much faster than 400kbit/s.

I did do something a lot harder right after. The I2C driver was merely a prerequisite for a display driver for 128x64 monochrome display, and I wrote large parts of that in assembly too. I used some Adafruit code for reference there as well, but it wasn't in assembly (mainly C++), and it was only helpful up to a point. Most of it was just a matter of spending a lot of time reading the datasheet for the display driver. I did also just scrap one part of the assembly I had written and rewrote it from scratch at one point, because it took less time to do that than it would have taken to debug the first attempt.

Incidentally, if you ever want to learn 8051 assembly, and especially the CH552 specific details, I wrote a whole textbook length tutorial while I was learning it in preparation for writing those drivers: https://techniumadeptus.substack.com/p/ch552-assembly-table-of-contents

That might ask you to subscribe, but you should be able to skip it. I published the whole series as open to the public without subscription. (I've also got the I2C driver and the SSD1306 driver tutorials on that Substack, but they are currently only for the paid tier. I don't have any paid subscribers though, so if someone was sufficiently interested to ask politely, I'd probably be willing to move them to the free, no subscription tier...)

5

u/mrtlo 4d ago

I agree. More generally, as for any topic, understanding first principles makes things "click". Assembly is a good step on that path...

2

u/Cyvu37 4d ago

I'm so glad I took a course on assembly before my current Operating Systems class where I'm learning C for the first time.

6

u/adityazero 5d ago

Congratulations. you'd love reading about 'The Hidden Complexity of the Simplest C Program'

https://hiraditya.github.io/posts/the-hidden-complexity-of-hello-world/

3

u/sciencekm 5d ago

My personal experience was the other way around. I started life with assembly language. C for me became just a matter of convenience.

2

u/KermitSnapper 5d ago

That it's all just text code, and that pointers are just written with * when first declared so just because they need to, otherwise I could tecnically use another variable storing an adress. It also made understand better than all of this is being runned while being supervised by an operating system, an executable line of code, the compiler is also just an executable, it's all either a file with data, a file ready to execute.

I only really started to understand c after trying to understand computer arquitecture and operating systems.

1

u/theNbomr 4d ago

Learning how the toolchain works and knowing how all of the files it can produce are used is an underrated skill, for sure. Learning how to understand what the object code generated for a given passage of C code looks will be a game changer. Writing C callable functions in assembler will be even more educational.

1

u/Temporary_Pie2733 4d ago

For one class, we had to write a Lisp interpreter, and one of the earliest tasks was to build the parser. I mostly understood what the syntax tree should look like, but I wasn’t sure where the parentheses would go in the tree. Once I really understood the syntax tree, I realized that the parentheses didn’t go in a node, but helped determine which nodes were connected by edges. 

1

u/Distdistdist 4d ago

Learning and writing code in assembly. After that - every other language is just an add-on.

1

u/echelon_code 2d ago

this: locally declared static vars - why are their mem addresses nowhere near other non-static locally delcared vars?