Bedrock of Software – Part 1: The Origins of C

In the world of software engineering, there is a constant change. Anything we learn has a potential to get redundant just in a matter of years. A lot of languages, methodologies, techniques, tools, frameworks, libraries came in with a huge noise and went away silently. Very few things manage to live for a decade. However, there is one thing which has been there for more than half a century, and remained unchanged. It is the core of all operating systems, and also all compilers and interpreters of unexceptionally all programming languages, and it is also the father of almost all mainstream languages we use today. Yes, we are talking about the C Programming Language. The bedrock of software as we know it.Before going into the details, I want to dedicate this series to my older brother Ali Cihan, who encouraged me to learn C programming language, and guided towards the right direction in programming when I was a 16 year old boy. I am really grateful to him. In this very first part of this blog post series, I will be talking about the brief history and birth of C. Part 1 – Origins of C It all started in Bell Labs. Bell Labs is a research and development company in US. It is credited with transistor, laser, photovoltaic cell, radio astronomy and many more. They are not limited with electronics, the Unix operation system and C programming language are also developed in Bell Labs. C is created by Denis Ritchie and it mainly influenced by another language used in Bell Labs, called B. B was designed and created by Denis Ritchie’s colleague, Ken Thompson. The name B refers to the word Bell, and the name C is chosen since it is the letter after B. Both B and C were following a tradition coming from a language family called ALGOL (Algorithmic Language) developed in 1958. The reason of the need for C programming language was clear, all existing programming languages had a deficiency in terms of portability and efficiency for a large scale system-level project. For instance, Assembly language was bounded with the architecture of the specific hardware it is written for. This means that every single piece of code needs to be re-written for a specific hardware. In response to Assembly, languages like B and BPL were developed. However, they weren’t covering the need. B was lacking of data structures, for instance. Furthermore, it had performance issues in system-level programming. BPL had a verbose syntax which makes large scale projects very difficult. C changed the game since it had readability and writability of a high level language and capability and performance of a low level language. Furthermore, its structure allowed to write reusable code and structure large-scale solutions. All these made C the monopoly of system programming for almost half a millennia. Basic Aspects of C Let’s look at some details which made C as an unbeatable language. Direct Memory Access: C has direct access capability to memory using pointers. This allowed developers to write code that could directly manipulate hardware and memory, similar to assembly language. High-Level Constructs: C offered high-level programming constructs such as loops, conditionals, and functions. This combination allowed programmers to write better code without sacrificing the ease of use found in higher-level languages. Hardware Independence: One of the primary design goals of C was portability. Code written in C could be compiled and run on different types of hardware with minimal changes. This was an important advancement over Assembly. Standard Library: C’s standard library provided a collection of functions for performing common tasks, ensuring that these functions would behave consistently across different systems. This further enhanced the portability of C programs. Minimalist Design: C was designed to be simple and minimalistic. It included only the essential features needed for system programming, avoiding the complexity and verbosity of languages like PL/I or ALGOL. Type System: Although simpler than modern type systems, C’s type system was stronger than those of some contemporaries like BCPL. It included primitive data types (int, char, float, etc.) and allowed for the creation of complex data types through structs and arrays. The introduction of a better type system helped catch errors at compile time, improving the reliability of code. Control Structures: C included a rich set of control structures (such as if-else, switch, for, while, and do-while loops), which facilitated structured programming and improved code readability compared to the goto-heavy styles of assembly language and some older high-level languages. Modularity: C introduced the concept of modular programming through functions. Programs could be broken down into smaller, reusable functions, making code more organized and easier to manage. Standardization of C ANSI, the American National Standards Institute, set the standards for C. This helps developers work together better, makes different systems compatible with each other, and encourages using the best methods. ANSI set 3 standards for C and these versions provide a standardized framework for C to ensure consistency and compatibility across different platforms and implementations. First standard was ANSI C89/C90. It was approved by ANSI in 1989 and later adopted as an international standard by ISO in 1990. ANSI released an updated version of the standard in 1999, known as ANSI C99. This version introduced several new features and improvements to the language, such as inline functions, variable-length arrays, and new data types like long and bool. ANSI C11, released in 2011, brought further enhancements to the language. It introduced features like Generic Selection, Multi-threading support, and Atomic operations. ANSI C11 aimed to improve the expressiveness, safety, and performance of the language while maintaining backward compatibility with previous versions. In summary, the combination of strong features made C a revolutionary language for its time. It bridged the gap between low-level hardware control and high-level programming abstractions. It has been offering portability, efficiency, and simplicity, furthermore it still does. These aspects not only distinguished C from the other languages of its time, but also set the foundations for many future programming languages. This is why it deserves to be called as bedrock of the software as we know it. Suleyman Cabir Ataman, PhD

Bedrock of Software – Part 2: C and Unix – A Symbiotic Relationship

The best way to describe the relationship between C and Unix will be mutual evolution. Both were developed at Bell Labs and each played a unique role in the other’s success. This symbiotic relationship not only led to the widespread adoption of both C and Unix but also set the foundations of modern computing. Or computing as we know it. Unix began as a small project led by Ken Thompson and Dennis Ritchie at Bell Labs. Remember, Dennis Ritchie is also the inventor of C programming language. The primary principle was to be a simple, multi-tasking, multi-user operating system. In 1969, Thompson and Ritchie created the first version of Unix in assembly language. Even though this was an effective proof of concept, it had significant limitation like poor portability and maintainability since Assembly was specific to a hardware. As Unix evolved, the need for a more efficient and portable way of writing it became apparent. A high-level language was necessary to overcome the constraints of assembly language. Unix required a language that could handle system-level tasks easily and efficiently. C had already designed with these needs in mind. It had features that supported low-level programming, such as direct memory access and pointers. The way Unix drove the evolution of C begins here, as Unix became more complex, C is modified accordingly by adding new features and optimizations. This iterative process led to the standardization of C and the changes are fixed at some point with ANSI C in 1989. C’s efficiency allowed Unix to perform well, even on the limited hardware of the time. C’s ability to produce optimized machine code was the key factor in Unix’s success. Writing Unix in C made the codebase more manageable and easier to understand when we compare it to Assembly. This made ongoing development easier and contributed to the performance and portability of Unix. In summary, the symbiotic relationship between C and Unix has left a lasting legacy in the world of software. Actually two since Unix led Linux, which is the bedrock of internet and cloud computing. Together, C and Unix have influenced countless aspects of modern software development. Suleyman Cabir Ataman, PhD

Bedrock of Software – Part 3: The Influence of C on Modern Programming Languages

Welcome to the third part of our blog series, “C, Bedrock of Software.” In the first part, we explored the origins of C. In the first part, we discussed its creation at Bell Labs and its role in the development of Unix. In the second part, we examined the symbiotic relationship between C and Unix. We saw how they evolved together, shaping the future of computing. In this part, we will focus on how C has influenced modern programming languages. We will see its impact on popular languages like Java, C#, C++, Objective-C, and others. This will show how C’s legacy continues in today’s programming world. Direct Descendants of C C++ Bjarne Stroustrup developed C++ as a spin off from C. He wanted to add object-oriented features to C. C++ retained much of C’s syntax and structure. This made it easy for C programmers to transition to C++. They did not have to learn a completely new language but a new programming technique and approach. C++ introduced several key improvements. It added new concepts which doesn’t exist in C in order to maintain object oriented principles, like classes and inheritance. Polymorphism was another important feature which enables functions to operate on objects of different classes. These enhancements made C++ a language for building complex software in an object oriented fashion. Objective-C Objective-C added Smalltalk-style messaging to C. This made it a powerful language for developing applications on Apple’s platforms. Objective-C played a crucial role in the development of macOS and iOS. It combined C’s efficiency with the flexibility of object-oriented programming. Objective-C’s impact on the Apple ecosystem was significant. It became the primary language for developing applications for Mac and iOS devices. This led to the creation of many popular applications and helped establish Apple’s software development environment. On the other hand, Objective C also has its object oriented elements from a forgotten language called SmallTalk. Influences on Modern Languages By influencing languages like C++ and Objective-C, C has left a lasting legacy. Its core features continue to shape modern programming languages and practices. Now, we will explore more examples of C’s influence on contemporary programming. Java Java borrowed many elements from C and C++. It adopted their syntax and semantics for example. This makes Java familiar to C programmers. However, Java introduced a powerful standard library and a virtual machine. This allowed Java programs to run on any platform without modification. Java improved upon C’s manual memory management with garbage collection. This automated process reduced the risk of memory leaks and pointer errors. Developers no longer needed to manually allocate and free memory, which simplified coding and improved program stability. C# C# was designed by Microsoft with many similarities to C and C++. Its syntax is close to these languages, easing the learning curve for C programmers. However, C# includes several modern features to support application development on the .NET framework. C# introduced properties, events, and a strong type system. Properties simplified data encapsulation. Events enabled responsive and interactive applications. The strong type system enhanced code reliability and reduced runtime errors. These features made C# a powerful tool for modern software development. PHP PHP was designed for web development and scripting, making it a popular choice for building dynamic websites. It borrowed from C and Java while focusing on server-side programming. Over time, PHP evolved into a powerful language for web applications, with widespread support for databases and frameworks. It has still been one of the most popular languages in use and it is the primary language. used in backend. I wrote a post about PHP in the past. Perl Perl may not be familiar for the new generations but once upon a time, it had been known for its text-processing capabilities, drew heavily from C and shell scripting. It became a popular choice for system administration and web development. Perl’s flexible syntax and support for regular expressions made it a go-to for quick scripting and powerful automation tasks. As of 2020s, it is one of the language at the edge of extinction. D As one of my favourite programming languages, D emerged as an alternative to C++, aiming to simplify programming while maintaining efficiency. It retained the power of low-level programming but offered modern features like garbage collection and better modularity. D struck a balance between performance and ease of use, appealing to systems programmers. Check my blog post about D. Swift Swift was created by Apple to modernize application development for its platforms. It was designed to be safer, more expressive, and faster than Objective-C. Swift’s simpler syntax and focus on performance made it the new favorite for building apps in the Apple ecosystem. JavaScript JavaScript, though dynamically typed and prototype-based, borrowed C-like syntax. This familiarity helped programmers transition to JavaScript easily. Initially a simple scripting language, JavaScript has evolved into a powerful tool for web development. JavaScript started as a client-side scripting language. Today, it is used on both client and server sides, thanks to environments like Node.js. This evolution has made JavaScript essential for modern web applications. TypeScript TypeScript builds on JavaScript, adding static typing and modern development tools to improve large-scale application development. It enables better error checking and cleaner, more maintainable code while still being compatible with existing JavaScript libraries and projects. Go (Golang) Go, developed by Google, was influenced by C’s simplicity and efficiency. It added modern features like garbage collection and concurrency primitives, making it suitable for contemporary systems programming. Go’s concurrency model is built around goroutines. These are lightweight threads managed by the Go runtime. This approach simplifies concurrent programming compared to traditional threading models in C. Rust Rust aims to provide the performance of C while ensuring memory safety. Its ownership model prevents common errors like null pointer dereferencing and data races. Rust’s borrow checker enforces strict rules on memory usage. This ensures safe memory management without needing a garbage collector. Rust’s approach combines safety with high performance, making it a strong choice for systems programming. Conclusion C has significantly influenced many modern programming languages. Its syntax and features are found in languages and its impact is evident in systems programming, education, and software development. C is likely to continue influencing future programming languages. Its principles of simplicity, efficiency, and control will remain relevant. Emerging languages may build on C’s foundation while introducing new paradigms and features. Understanding C and its legacy is crucial for any programmer. It provides insight into the evolution of programming languages and practices. Learning C can enhance one’s programming skills and appreciation for the history of software development. Suleyman Cabir Ataman, PhD

Bedrock of Software – Part 4: Operating Systems Written in C

In the previous posts, we explored how C laid the groundwork for modern programming languages and shaped the software landscape. We’ve looked at C’s influence on languages and traced its role as the foundation for today’s development tools. Now, we turn our attention to another critical area where C’s impact is undeniable: operating systems. We have already talked about the relationship between C and Unix here. However, the relationship with C and operating systems are not limited to Unix. Unexceptionally, all operating systems we use today (Windows, Linux, Mac OS, IOS, Android etc.) are either primarily or entirely written in C. So C is has a monopoly on writing operating systems. Of course, it is not an accident. C became the language for operating system development because it offered the right mix of control and flexibility. It provides programmers low-level access to hardware while providing high-level abstractions that made writing complex software manageable. This balance allowed C to be both powerful and efficient. UNIX UNIX was a groundbreaking invention in the foundation for modern computing. Originally developed in assembly language, UNIX was rewritten in C, which allowed it to become portable across different hardware. This move made UNIX one of the first truly adaptable operating systems, as it could be recompiled on various machines without needing significant changes. By using C, UNIX established a model of simplicity and efficiency that would influence system design for decades to come. In the second part of this series, we explored the symbiotic relationship between UNIX and C. The development of C was driven by the needs of UNIX, while UNIX’s portability spread C’s influence. As a result, C became the language for future operating systems. It also inspires the design of later systems like Linux, Windows, and macOS. UNIX’s use of C set a precedent for how programming languages and operating systems could evolve together, shaping the direction of software development. Linux The Linux kernel (the heart of the Linux operating system) is written in C. C’s ability to provide direct access to memory and hardware-level control made it an ideal choice for kernel development. It allows developers to fine-tune system performance, manage resources, and handle low-level tasks that are critical for an operating system’s stability and speed. C’s simplicity and flexibility played a key role in Linux’s rise. Its straightforward nature made it easier for contributors around the world to understand and modify the code. As a result, Linux became a collaborative effort, with developers from different backgrounds enhancing and expanding it. This accessibility, enabled by C, helped Linux grow into one of the most influential operating systems today. While Linux is widely used in servers and desktop computing, its impact extends to many other devices that run custom Linux-based operating systems. For example, the Nintendo Switch gaming console uses a Linux-based operating system to manage hardware resources efficiently and deliver gaming performance. Other devices like smart TVs, routers, and even cars also run custom versions of Linux. As we know, Linux is an open source operation system and you can find Linux kernels source code here. Android Android (currently the world’s most widely used mobile operating system) is built on a modified version of the Linux kernel. This provides Android with the same low-level control over hardware that makes Linux efficient especially in an environment like mobile devices which requires performance. Beyond the kernel, C plays a critical role in Android’s performance, particularly in areas where high efficiency is needed, such as gaming and multimedia processing. Android’s Native Development Kit (NDK) allows developers to write parts of their apps in C or C++, enabling more direct access to system resources and providing better performance for CPU-intensive tasks. Windows The development of the Windows NT kernel marked a significant shift for Microsoft. It aimed to create a modern, stable, and scalable operating system for ordinary users. Not too difficult to guess, C played an important role in building this foundation too. The decision to use C for the kernel allowed developers to handle critical system tasks with efficiency. C’s close-to-the-metal capabilities gave Windows NT the performance it needed to compete in both personal and enterprise environments, where reliability and speed were crucial. While later versions of Windows mainly used C++ for higher-level functionalities, C still remained essential to the core. C++ is not too far from C after all. The kernel continued to rely on C for low-level tasks, such as direct hardware communication and interrupt handling. This hybrid approach ensured that Windows could offer a powerful and stable core while taking advantage of C++’s object-oriented features for building higher-level applications. macOS / IOS C played a key role in the development of macOS and iOS as well. They both are built on the Darwin operating system. Darwin is a Unix-based system and it relied heavily on C for its core components. This allowed Apple to create a powerful and stable foundation that could handle the performance demands of modern computing. C’s influence extends beyond the kernel. Many system-level libraries and frameworks that power macOS and iOS were also written in C or C-derived languages. Solaris Solaris is another operating system written in C. Many of you may not be familiar with it. It is developed by Sun Microsystems and it is just another Unix-based operating system. It is known for its scalability for enterprise environments requiring high performance and stability. After Oracle acquired Sun and it is rebranded as Oracle Solaris. Other Embedded Operating Systems and C C remains the dominant language in embedded systems development as well. From microcontrollers in everyday appliances to critical systems in medical devices, C allows developers to optimize performance and ensure reliability in even the most resource-constrained scenarios. In Real-Time Operating Systems (RTOS) such as those in automotive systems or industrial automation mainly rely on C’s ability to execute tasks quickly and predictably without unnecessary delays. Conclusion In conclusion, C’s role in operating systems development is unparalleled, having shaped the very foundation of the digital world we live in today. From UNIX to modern giants like Linux, Windows, macOS, and Android, C’s balance of power and simplicity has made it the language of choice for system-level programming. Its influence extends beyond general-purpose operating systems, powering embedded systems and real-time applications that demand precision and reliability. As technology continues to evolve, C remains a cornerstone of computing, ensuring performance and efficiency across diverse platforms and devices.