Differences Between C Language and Assembly Language

Differences Between C Language and Assembly Language

Previous Articles

πŸ‘ Five Stages to Assess Your Circuit Design Ability

πŸ‘ How to Learn Circuit Design from Scratch?

πŸ‘ Detailed Explanation of Four Schemes for Microcontroller Key Design

πŸ‘ 17 Common Circuit Design Modules for Microcontrollers

πŸ‘ Analysis of the Minimum System of Microcontrollers (Power Supply, Crystal Oscillator, and Reset Circuit)

πŸ‘ Detailed Explanation of Six Simple Switch Power Supply Circuit Diagrams

πŸ‘ Five Circuit Diagrams for Driving Buzzers

πŸ‘ Classification and Differences of Capacitors

πŸ‘ Four Things You Need to Know About PCB Differential Pairs

πŸ‘ Summary of Relay Driver Circuits

πŸ‘ Complete Guide to Stepper Motor Driver Circuits

πŸ‘ Complete Guide to Driving Circuits for Digital Tubes

πŸ‘ Discussing Several Debugging Schemes for Microcontroller Development

πŸ‘ How to Create an IT Project Plan

πŸ‘ Complete Guide to Ultrasonic Generator Circuit Diagrams

πŸ‘ Complete Guide to A/D Converter Circuit Diagrams

πŸ‘ Complete Guide to USB to TTL Circuit Diagrams

πŸ‘ Easy to Understand Explanation of SPI Bus

πŸ‘ Understanding STM32 Memory

πŸ‘ Do You Know the Development Process of the 51 Microcontroller?

πŸ‘ 485 Communication Circuit Diagram

πŸ‘ Explanation of Four Types of DC Motor Driver Circuit Diagrams and Design Ideas, with Pictures!

πŸ‘ Using the 51 Microcontroller to Output PWM

πŸ‘ Overview of 51 Microcontroller Register Functions

πŸ‘ Basic Circuit Principles of Transistors

πŸ‘ Analysis of Microcontroller Learning Path

πŸ‘ 51 Microcontroller Key Control Output PWM Duty Cycle

πŸ‘ Principle of the 51 Microcontroller P0 Port

πŸ‘ What Size Should PCB Silkscreen Be? Do You Know?

πŸ‘ What Are the Differences Between 51 Microcontroller and 52 Microcontroller?

πŸ‘ Microcontroller Project Development Process, Experience Sharing on Microcontroller Learning Path

πŸ‘ Analysis of Microcontroller Learning Path

πŸ‘ Principle of the 51 Microcontroller Crystal Oscillator Circuit

πŸ‘ Experienced Insights on How to Read English Data Sheets

πŸ‘ Differences Between Hex and Bin Files in Microcontrollers

πŸ‘ Detailed Explanation and Selection of Pull-Up and Pull-Down Resistors in Microcontrollers

πŸ‘ Some Words for Beginners in Microcontroller

πŸ‘ Video Analysis of Matrix Keyboard Circuit Principles

πŸ‘ Differences Between Harvard Architecture and Von Neumann Architecture

πŸ‘ What Is the Relationship Between LEDs and Digital Tubes? Do You Know?

πŸ‘ Troubleshooting Reasons for Microcontroller Program Download Failures

πŸ‘ What Should Beginners in Embedded Systems Pay Attention To? The Answers Are Here

πŸ‘ Analysis of the Principle of Multi-Digit Digital Tube Dynamic Scanning

πŸ‘ Analysis of DHT11 Temperature and Humidity Sensor Principles

πŸ‘ Explanation of the Measurement Principle of Ultrasonic Module HC-SR04 Circuit

πŸ‘ Differences and Choices Between Microcontrollers and ARM?

πŸ‘ Understanding of Stack, Static, and Dynamic Memory

πŸ‘ What Are the Differences Between STM32 Microcontroller and 51 Microcontroller?

πŸ‘ Analysis of USB Female Connector Pin Definitions

πŸ‘ What Types of USB Sockets Are There, and How Are Pins Defined? Do You Know?

πŸ‘ How to Differentiate Rising Edge, Falling Edge, Low Level, and High Level

πŸ‘ Sharing Experiences on Connecting Microcontrollers to Bluetooth 4.0

πŸ‘ How Many Microcontroller Interview Questions Do You Know?

πŸ‘ Sharing Experiences from a Production Line Worker to a Microcontroller Engineer

πŸ‘ Setting PWM Frequency and Duty Cycle in STM32

πŸ‘ Correct Methods for Using 3.5mm Headphone Jacks

πŸ‘ Introduction to the Internal Structure and Functions of MCS-51 Microcontroller

πŸ‘ Detailed Explanation of SFR and SBIT Keywords in Microcontrollers

πŸ‘ Issues of Heat and Reset in STC Microcontrollers

πŸ‘ Common Warnings in Keil, How Many Have You Encountered?

πŸ‘ How to Visually Understand PID Algorithms, Look Here

πŸ‘ 7805 Voltage Regulator Circuit Diagram

Having engaged in embedded system development for many years, I have accumulated considerable experience in software, from early programming in microcontroller assembly language to later writing C++ interface programs. It is precisely because of years of practical experience that I have formed my own understanding of the principles and applications of assembly and high-level languages, which is something I often ponder. However, I have never documented these thoughts in writing. The reason I write these words today is to summarize them for future reference.

In fact, the differences between C language and assembly language have always been a topic of great interest among programmers. If you ask a programmer this question, they might answer: β€œC language has good readability, code is easy to maintain, and easy to develop; programs written in assembly language are not easy to understand, have poor maintainability, but high execution efficiency.” This answer is not wrong, but it is merely a summary and lacks depth. For example, why is the execution efficiency of assembly language higher than that of C language? What makes C language more readable? Can assembly language not also use comments to improve readability? These questions are not simple to answer and cannot be explained in a few words; they require a thorough analysis of the essential differences between assembly and C.

First, let’s talk about assembly. Programmers who have written assembly know that “Assembly language is essentially a mnemonic for machine language.” This statement needs to be interpreted as follows: 1. The CPU can only execute the instruction set it supports, and each instruction in that instruction set is a sequence of binary numbers, which is an ordered combination of “0” and “1”; 2. The combination of “0” and “1” is inconvenient for programmers to remember, hence the mnemonics such as “MOV A, 0x40” are created. This means that when programmers write programs, they use “MOV A, 0x40” to replace a series of “0” and “1” sequences, making it clear that data from the unit “0x40” is moved into accumulator A. If it were a sequence of “0” and “1”, it would have no characteristics and would be hard for programmers to remember. This is the reason for the existence of assembly language.

The above explanation of assembly language essentially captures its essence. Once we understand the essence of assembly language, it is not difficult to comprehend that compiling assembly language into machine language executable by the CPU only requires a translation process since mnemonics correspond one-to-one with binary instructions. Next, we can explain why assembly language has higher execution efficiency than C language.

First, we need to understand one point: high-level languages like C target programmers, not CPUs. Why do I say this? The reason is simple: the CPU does not understand C language; it only recognizes instructions that exist in the form of “0” and “1”. Therefore, all syntax and code organization in C language assist programmers in writing code. Thus, after writing a program in C language, it must be compiled into machine language instructions that correspond to the respective CPU instruction set by a compiler.

Here comes the problem: we previously mentioned that assembly language and machine language correspond one-to-one. But what about C language? Of course, it’s not that straightforward. The syntax of C language is fixed, and a program written in C must follow many compilation rules to be converted into machine language instructions that the CPU can understand. For example, a for loop will correspond to several machine instructions that implement the for loop’s functionality, while a switch statement will also correspond to a segment of machine instructions.

I have experimented with writing a simple program in C, for example, one that only contains a for loop. The compiled code is almost identical to the optimal code written in assembly. However, as the code size increases, due to the constraints of the rules (which must be adhered to, otherwise it cannot be compiled), the code generated becomes much more convoluted compared to that written in assembly language. Although many modern C compilers optimize during compilation, it is impossible to achieve the same efficiency as assembly language, which corresponds directly to machine language. After all, assembly language can be understood as directly addressing the CPU; it is merely machine language represented with mnemonics.

The above is just one of the main reasons for the efficiency differences between the two languages. In fact, assembly language also has advantages in resource utilization. Assembly is a language that directly faces the CPU, and as long as it is within the supported instruction set, assembly language can flexibly manage every byte of special function registers, general-purpose registers, and storage units, even down to each bit. C language also has strong capabilities in memory usage and management, but it is still constrained by its syntax.

For example, in C language, there are no corresponding variable types for three-byte or five-byte variables; it’s either int or long, so every allocation must be a fixed number of bytes, inevitably leading to memory waste. Most assembly languages do not have such syntax; with the help of pseudo-instructions (which merely improve readability), assembly language programs can use variables of any byte size. Of course, it is much more complicated to handle than in C language, ultimately processing one byte at a time. Writing a program in C is easier, as you don’t have to worry about these details; the compiler will take care of it. However, the ease comes at the cost of waste. Inefficient memory usage can also affect the overall efficiency of the program.

Finally, let’s discuss pseudo-instructions. A programmer who is not adept at using pseudo-instructions to write assembly programs is not a good programmer, just as one who doesn’t use macros in C is not considered proficient. The value of pseudo-instructions lies in improving the readability of assembly language while simplifying assembly programming. For example, the most common use is to create names for immediate values instead of using binary or hexadecimal numbers; creating data tables; and defining global and local variables in ARM. I won’t elaborate on this, as different MCUs or CPUs have different pseudo-instructions.

Now let’s talk about C. The rich and practical statements in C language determine its flexibility and powerful code organization capabilities. With C, we can easily write large projects, and with the help of version control tools, collaborative programming becomes simple. Especially with the introduction of RT-OS, the framework for C programs has become more flexible, making it easier to add functionalities (tasks). All task control can be directly managed by the operating system, while programmers need only focus on writing the content of the tasks (which may include one or more functional modules) and setting task priorities, stack sizes, etc. Moreover, communication between tasks can be separated from the β€œglobal variables” menace, and can be achieved through semaphores, mailboxes, queues, etc. Why are global variables considered a menace? When the program size is small, global variables may be beneficial as they are convenient to access and modify.

However, once the program grows larger, and the source files multiply, if we rely on global variables for passing and storing shared values, disaster will strike. You will see thousands of global variables crisscrossing among various functions. If these variables were not created by you, it would be difficult to discern their purpose due to the sheer size of the system and their numerous appearances. Such a multitude of variables can lead to a sense of dread for many experienced programmers. This, however, sows the seeds for system-level crashes.

Due to the excessive number of global variables, which appear in too many places, it becomes challenging to fully account for where they might be modified. If any oversight occurs, the variable’s value could deviate from what we expect, and the consequences can be severe. Moreover, when global variables are pointers to arrays or the arrays themselves, some programmers may become confused by the multitude of these variables, easily committing the error of writing out of bounds on these global arrays, inadvertently altering unrelated variables. The resulting consequences could be errors or crashes, and due to the hidden nature of such issues, they can be very difficult to trace.

Thus, in large systems, the existence of an OS is fortunate; it not only helps us eliminate the menace of global variables but also assists programmers in organizing various functional modules more conveniently. It allows each task to be singular, thereby reducing the difficulty of programming. Writing larger projects in assembly language is fraught with challenges.

First, we must confront the global variable issue mentioned earlier, in addition to facing other difficulties, such as memory usage. In C language, programmers simply allocate various types of variables and can use them without concern; the compiler manages which memory units are used. However, when writing programs in assembly language, you must specify the memory addresses used. This leads to the necessity for programmers to have a thorough understanding of all memory usage because every memory unit’s usage must be explicitly stated, which is a characteristic of assembly language. Once the program size reaches a certain degree, planning the usage of memory itself becomes a challenging task, especially ensuring that there are no conflicts when used in various places. I have experienced this firsthand. Now, let’s imagine that if the program is too large, and we need several people to collaborate on its development, the complexity increases even more because, without the compiler’s assistance, programmers must negotiate memory usage rules. This is incredibly difficult since they only face a vast address space; dividing regions may be simple, but the interactions between programs create significant complications. Each programmer must provide their variable interfaces, as in assembly, these are merely memory space resources, as well as describe their functionalities. This workload is substantial, and if not done well, it is easy to make mistakes, and errors are hard to trace.

There are many more difficulties in writing programs in assembly compared to C. For example, assembly language is a low-level language, a one-to-one translation of machine language for programmers, so its functions are not as rich. In C language, writing a program for (13200.68/98.56)*256.24 can be directly represented as “double a; a=(13200.68/98.56)*256.24;” In assembly, it is not so straightforward; assembly typically does not directly support floating-point operations, and usually, a special function must be written to handle floating-point calculations. The result is that writing assembly programs is much more cumbersome than C, and it is not intuitive. Additionally, writing programs in assembly requires a higher level of skill from the programmer, as they must understand the memory structure, bus structure, functional modules, stack systems, interrupt resources, and mechanisms of the CPU or MCU; otherwise, they cannot proceed.

In conclusion, C language and assembly are fundamentally different; how could their distinctions be summarized in just a few sentences? Given the current situation, due to the maturity of IC technology, MCU storage resources are becoming cheaper, and operating frequencies are increasing, the demands for resource utilization and execution efficiency are not as stringent as before. Moreover, the functionalities that can be realized are becoming increasingly powerful. These factors have contributed to the rising status of C and C++ in embedded development. Even the programming of MCS-51 is predominantly in C language, thanks to the powerful and user-friendly tool KEIL. High-level languages that target programmers are more user-friendly than assembly languages that target CPUs. Given the hardware conditions, programmers naturally choose to program in high-level languages, which not only improves programming efficiency but also enhances code maintainability, making it very advantageous for writing large projects. Have you read through the entire article? If you liked it, please give it a thumbs up together.

Industry Communication Group

Differences Between C Language and Assembly LanguageWeChat Group

If the WeChat QR code is invalid, please contact WeChat xiaocaoxsd

Differences Between C Language and Assembly LanguageQQ Group

Disclaimer:Works reproduced in the public account are indicated as much as possible. All rights of the work belong to the original author and are not transferred by this site. If the author disagrees with the reproduction, please notify this site for deletion or correction. Reproduced works may have changes in title or content.

A Letter to Chip Fans:A large number of fans have yet to develop the habit of liking and sharing after reading. I hope everyone will take a moment to like and share as encouragement! It is not easy for one person to consistently publish articles, even original ones, and I have thought about giving up multiple times. Persistence is a belief, and focus is an attitude.

Differences Between C Language and Assembly Language

Leave a Comment