Advanced Embedded Programming: C Programming (Part 2)

Advanced Embedded Programming: C Programming (Part 2)

1. Daily Chat(It is said that articles go well with music)

At the beginning of the article, I have selected an older song by JJ called “Jiangnan” for everyone to reminisce. The first article in this series briefly discussed the process of converting C language to machine code, and provided an overview of why C language is chosen for low-level development. The knowledge points in this series may be quite scattered, as they are small details in C programming that are not substantial enough to form independent articles. Therefore, the author has collected these small knowledge points and introduced them in the form of subheadings. Larger knowledge points in C language will be shared as independent articles and will not be presented in this series.

Advanced Embedded Programming: C Programming (Part 2)

Now, let’s get into today’s topic:

1. Various Forms of the main Function

Careful readers should have noticed that there are quite a few forms of our main function, such as void main(void); int main(void); int main(int argc, char *argv[]); etc. The different forms of the main function are mostly related to the compilation environment. For most microcontroller systems, it does not take parameters or return values, while in systems with an OS, applications generally take parameters and return values. This allows the parent process to provide parameters, and the return value can reflect its running status, such as in Linux or DOS commands in Windows.

Let’s take a look at the parameters of the form int main(int argc, char *argv[]). The other forms of void are merely to restrict the passing and returning of parameters. The main function is essentially the same as other ordinary functions, but when we run the corresponding program from the command line, the way parameters are passed differs. For example, here is a sample I ran in Windows:

#include <stdio.h>
#include <stdlib.h>
/*********************************************
 * Function: main
 * Author : (WeChat: Last Bug)
 ********************************************/
int main(int argc, char *argv[]) {
    int i = 0;
    printf("argc:%d\n",argc);
    for(i = 0;i < argc;i++)
    {
        printf("argv[%d]:%s\n",i,argv[i]);
    }
    return 0;
}

Running result:

Advanced Embedded Programming: C Programming (Part 2)

To briefly explain:argc represents the number of pointers in the array, and each pointer in argv corresponds to a parameter string, including the running path. Once we understand the principles of these two parameters, we should not neglect them. In fact, the so-called powerful algorithms or codes are built up from small tricks, so in our future related projects, we can use this parameter passing method for ordinary functions to make our parameters more flexible.

2. Structures and Unions Can Be Assigned Directly

Everyone knows that arrays in C language cannot be assigned directly. Therefore, most of us have practiced loop statements very well when learning arrays, as we need to assign values one by one. We might subconsciously think that data types composed of multiple basic data types, such as structures or unions, should also not be assigned directly. Let’s write some code to test this:

#include <stdio.h>
#include <stdlib.h>
/************************************
 * Function: Data Type Definition Area
 * Author :(WeChat: Last Bug)
 ***********************************/ 
typedef struct _tag_sTest
{
    int a;
    int b;
    int c;
} sTest;
typedef union _tag_uTest
{
    int a;
    int b;
    int c;
} uTest;
/************************************
 * Function: main
 * Author :(WeChat: Last Bug)
 ***********************************/ 
int main(int argc, char *argv[]) {
    // Define variables
    sTest stTest1;  
    sTest stTest2;
    uTest unTest1;
    uTest unTest2;

    // Copy stTest1
    stTest1.a = 1;
    stTest1.b = 2;
    stTest1.c = 3;

    unTest1.a = 4;

    // Directly assign structures and unions
    stTest2 = stTest1;
    unTest2 = unTest1;

    // View running results
    printf("stTest2.a = %d\n",stTest2.a);
    printf("stTest2.b = %d\n",stTest2.b);
    printf("stTest2.c = %d\n",stTest2.c);

    printf("unTest2.c = %d\n",unTest2.c);

    return 0;
}

Compilation succeeded, and the running result is as follows:

Advanced Embedded Programming: C Programming (Part 2)

Analysis: This proves that our structure and union variables can be assigned directly. Some may wonder what the benefit is, as it seems similar to assigning values one by one. However, it is not the case. The intuitive benefit is that for variables with many structure members, direct assignment can save a lot of code and improve readability. Additionally, it is very useful for passing parameters and returning values directly as function arguments, which I will mention again later.

However, we need to note that direct value assignment for structures can only be done during initialization for overall assignment, and direct value block assignment is not allowed in other places, such as stTest1 = {1,2,3}; but variable assignment as shown in the example is allowed. This is similar to arrays.

3. Function Return Value Issues

In our daily programming, we all know that our functions can only return one value (addresses can also be considered a special value). When we want to return multiple values from a function, how should we handle it? Here, the author summarizes a few solutions for your reference:

1) Use a structure, as mentioned in the previous section, which I find quite convenient;

2) Use global variables to pass parameters;

3) Use pointers to pass parameters, generally without needing to return data. However, be careful not to return the address of a local variable, as it will be released once the function ends.

4. Today’s Summary

Today, we discussed several small examples, mainly to encourage everyone to dare to try and think about some conventional issues, and gain useful knowledge and skills from them. As a programmer, I believe that the ability to think, summarize, and abstract to a certain extent determines the quality of the code.

That’s all for today. Thank you for your attention and support. I hope everyone can conquer bugs and get off work early. This is the WeChat account: “Last Bug”. See you next time!

Advanced Embedded Programming: C Programming (Part 2)

Recommended Articles Click the blue text to jump

【Series】Embedded Programming “Advanced Path”–C Language Part (1)Advanced Embedded Programming: C Programming (Part 2)

Embedded Programming “Refactoring” Code (C Language Version) Advanced Embedded Programming: C Programming (Part 2)

☞Common Program Framework for Microcontrollers: Time-Slicing Polling (Detailed Code) Advanced Embedded Programming: C Programming (Part 2)

☞【Series】Learning Microcontroller Driver Programming through “Library Files” (5) – Final ChapterAdvanced Embedded Programming: C Programming (Part 2)

Why Functions or Variables are Generally Not Defined in .h Files in C Language? (Essence)Advanced Embedded Programming: C Programming (Part 2)

☞Step-by-Step Guide to Writing Modbus-RTU Protocol (Theoretical Part)Advanced Embedded Programming: C Programming (Part 2)

☞Memory Saving Techniques in Microcontroller Development (C Language Version)Advanced Embedded Programming: C Programming (Part 2)

Leave a Comment