Why I Still Reach for C for Certain Projects
The Project That Made Me Choose C Again
So a while back I got tired of xserver and decided to give wayland a try. I use Arch (BTW) with a tiling window manager (dwm) and I wanted to try something new, since I had a couple of annoyances with xserver. I’ve heard some good things about wayland so I thought you know what, why not let’s give it a shot.
After 30-45min my Arch and Hyprland setup was done and ready to go. I was pretty happy with it, but I was missing some features I’ve previously had such as notifications for when somebody posts new content to their RSS feed. I quite like RSS feeds I use them to keep up to date with blogs, news, streams, releases etc. So I thought to myself, why not write a small program that checks my RSS feeds and sends me a notification when there’s something new.
Now the way I was gonna go about this was pretty simple. I would write a simple C daemon that would run in the background, check my RSS feeds on a random interval between 5-15min and if there was something new it would send out a notification using notify-send
. Then comes the tricky part I wanted swaync
to allow me to offer two buttons on the notification, one to open the link in my default browser and one to ignore the notification and mark it as ignored in a flat file on my system so that I could see if I have to remove certain feeds that I tend to ignore a lot.
Now here’s the problem, you can’t really do that with swaync
, I mean it does support buttons but it doesn’t really let you handle the button clicks in a way that would allow you to do what I wanted. So I had to come up with a workaround. The workaround was to have another C program run as a daemon that would listen on the DBus for a very specific notfication that would contain an action with a string of openUrl("url")
or ignoreUrl("url")
and then handle the action accordingly. This way I could have swaync
send out a notification with the buttons and when the user(me) clicks on one of the buttons it would send out a DBus notification that my second daemon would pick up and handle.
Why C Was the Right Choice Here?
Now you might be wondering why I chose C for this project and not something like python which would allow me to write this specific program much faster and enjoy the rest of my weekend. Well my answer to you is simple, I don’t like python and I didn’t feel like wasting multiple 100s of MBs of RAM for something this simple and small.
In fact I DID write it in Python and Go first with their respective DBus libraries, both were super easy to work with and I had an initial working prototype within less than an hour. But as I ran a simple htop
I saw that the python version was using around 150MB of RAM and the Go version was using around 50MB of RAM. Now don’t get me wrong, I’m not on an old thinkpad I have RAM to spare 32Gb to be exact. But why waste it on something this small and simple.
Plus C is just so much more fun and exciting to work with. So I set up my C project which was just a simple Makefile
and a couple of .c
and .h
files. I imported dbus/dbus.h
and got to work. Now I’d be lying if I said it took me no time at all, in fact it took me roughly 3-4h which is a lot longer than python or Go. But in the end I had a working prototype that was using around 1-2MB of RAM and was super fast and responsive. I also got to brush up on my DBus skills which were a bit rusty since I hadn’t worked with it in a while.
Now getting a simple program like that from 150 to 50 to 1-2Mb of RAM usage is a huge performance improvement and it really showcases the power and strength of C as a programming language. Look at this this way I may have spent multiple hours longer writing this program in C but it will just continue to run in the background using a fraction of the resources that python or Go would have used for a long time to come.
Additionally this probably won’t be the only modification I make to my system now imagine if I were this lackluster with 10-20 small programs that I run in the background and let’s make a wild assumption that each of those programs would use about 50-200Mb of RAM. Now we’re looking at 500-4000Mb of RAM usage, or precisely one chrome tab!
No I don’t think that’s an acceptable tradeoff for a couple of hours of my time. So in the end I think C was the right choice for this project and I’m pretty happy with the result.
Why Modern Languages Aren’t Always the Best Fit
That long rant above is a cute story / anecdote. But I feel like it also highlights a bigger issue that developers face today. A lot of times we just wanna complete a certain task as quickly as possible and have it running before we’ve had our second coffee. I get it we’re all busy people and when resources are as cheap as they are today saving a few Mb of RAM or a few ms of CPU time isn’t really a big deal.
But there is something so nice and satisfying about writing a small program in C that does exactly what you want it to do and nothing more. It’s like a breath of fresh air in a world where everything is becoming more and more bloated and resource hungry. It feels a bit zen taking everything down to the bare minimum and just focusing on the task at hand.
I’d liken developing in C to woodworking, you have to be precise and careful with your cuts, but in the end you get a beautiful product that you can be uniquely proud of. Sure you could go pick up a flat pack from your local IKEA and have a nice looking table within an hour. But it will be souless and generic and not really made well, not something you can proudly say to your visitors “Hey I built this myself”. I mean you could… but they probably won’t really be as impressed with your flat pack assembly as if you were to show them a hand crafted table you made yourself.
C Excels in Low-Level System Programming and Efficiency
So maybe the example project that I described above in the beginning of the article is too rickety or not really high brow enough that’s fair I get that. But even if you think my project was stupid or silly or could have been done better or easier there is no denying that C simply is the gold standard for low level systems programming and efficiency.
C gives you unparalleled control over system resources, memory management, and performance optimization. This makes it the go-to choice for developing operating systems, embedded systems, and performance-critical applications where every byte of memory and every CPU cycle counts.
For example, the Linux kernel, which powers a vast majority of servers, desktops, and mobile devices worldwide, is primarily written in C. This is because C allows developers to write code that can directly interact with hardware and manage system resources efficiently.
If you drive any modern vehicle that was created in the past decade or so, chances are that you have multiple microcontrollers in your car that are running C code to manage everything from engine performance, emergency breaking systems (AEB, ABS), distance control systems (ACC) and so on. For these systems you are very limited in the amount of RAM usage you can afford and most importantly you can not afford too much latency or delays in processing.
Now how often have you heard about these systems failing and leading to fatal crashes? Not very often I’d wager. Of course safety standards, regulations and certifications play a big role in this but the choice of programming language is also a big factor. C is a mature and well-established language with a long history of use in safety-critical systems, making it a reliable choice for such applications.
It does it’s job exceptionally well and it does it with a very small footprint and most importantly you can run it in perpetuity on very limited hardware without worry over failure or issues due to resource exhaustion.
Real World Scenarios Where C Shines
Here are a few real-world scenarios where C is the preferred choice:
- Operating Systems: As mentioned earlier, the Linux kernel is written in C. Other operating systems like Windows and macOS also have significant portions written in C.
- Embedded Systems: C is widely used in embedded systems development for devices like microcontrollers, IoT devices, and automotive systems due to its efficiency and low-level hardware access.
- Game Development: Many game engines and performance-critical game components are written in C or C++ to achieve high performance and low latency.
- Database Systems: Many database management systems, such as MySQL and PostgreSQL, are implemented in C to ensure efficient data handling and query processing.
- Network Programming: C is often used for developing network protocols and applications due to its ability to handle low-level socket programming and efficient data transmission.
- Compilers and Interpreters: Many programming language compilers and interpreters are written in C to leverage its performance and low-level capabilities.
- High-Performance Computing: C is used in scientific computing and simulations where performance is critical, such as in numerical libraries and parallel computing frameworks.
- System Utilities: Many system utilities and command-line tools in Unix-like operating systems are written in C for efficiency and direct system access.
- Device Drivers: C is the language of choice for writing device drivers that allow the operating system to communicate with hardware devices.
- Cryptography: Many cryptographic libraries and algorithms are implemented in C to ensure high performance and security.
- Audio/Video Processing: Libraries like FFmpeg are written in C to handle multimedia processing efficiently.
- Web Servers: Popular web servers like Apache and Nginx are written in C to handle high loads and provide fast response times.
You get my point, C is everywhere and it excels in scenarios where performance, efficiency, and low-level system access are paramount.
When C Isn’t the Right Choice ?
Now as you can see I’m a pretty big proponent of C and you’ll often hear people who exclusively develop in C (sadly not me), say: “Anything and everything under the sun can be written in C”. Which is true, if you were to remove all programming languages from existence save one, my choice would always be C as we could potentially rebuild everything from the ground up.
However even I have to admit that C may not always be the best choice everything has it’s ups and downs.
So C may not be your best choice when:
- Rapid Prototyping: If you need to quickly prototype an idea or concept, higher-level languages like Python or JavaScript may be more suitable due to their ease of use and extensive libraries.
- Web Development: For building web applications, languages like JavaScript (with frameworks like React, Angular, or Vue) or Python (with frameworks like Django or Flask) are often preferred due to their ease of use and extensive web development libraries.
- Data Science and Machine Learning: Languages like Python and R are commonly used in data science and machine learning due to their extensive libraries and frameworks (e.g., TensorFlow, PyTorch, Pandas).
- Mobile App Development: For mobile app development, languages like Swift (for iOS) and Kotlin (for Android) are often preferred due to their platform-specific features and ease of use.
- Memory Safety: If memory safety is a primary concern, languages like Rust or Go may be more suitable due to their built-in memory safety features and garbage collection(Go).
- Ease of Learning: If you’re new to programming, languages like Python or JavaScript may be easier to learn due to their simpler syntax and extensive learning resources.
- Community and Ecosystem: If you need access to a large community and ecosystem of libraries and frameworks, languages like JavaScript, Python, or Java may be more suitable due to their extensive ecosystems.
Conclusion
So there you have it why I still reach for C for certain projects. It’s not always the fastest or easiest choice, but for small, efficient programs that need to run lean and mean, it often makes sense. C isn’t flashy or trendy, but it gets the job done, and sometimes that’s all that matters.
Curious to hear how others tackle similar projects C, Rust, Go, or something else?