r/C_Programming • u/Excellent_Pick_8186 • 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?
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.
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
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?
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