Keywords commonly used in embedded C language

1. static keyword

This keyword was also mentioned earlier, and its effect is powerful.

To understand the static keyword in depth, you first need to master the composition of the standard C program.

Standard C procedures have always consisted of the following:

1) Text section-the part of the machine instructions executed by the CPU, that is, your program. There is only one copy of a program; read-only, this is to prevent the program from modifying its own instructions due to accidents;

2) Initialize the data segment (data segment)-all global variables assigned initial values ​​in the program are stored here.

3) Non-initialized data segment (bss segment)-global variables that are not initialized in the program; the kernel initializes this segment to 0.

Note: Only global variables are assigned to the data section.

4) Stack-growth direction: top-down growth; automatic variables and the information (return address; environment information) that needs to be saved each time the function is called. This sentence is very important. There are often written questions that ask what is put on the stack.

5) Heap-dynamic storage allocation.

In the embedded C language, it has three functions:

Role one: In the function body, a variable declared as static maintains its value unchanged during the function call.

A variable defined in this way is called a local static variable: by adding the keyword static before the local variable, the local variable is defined as a local static variable. That is, the variables defined in the function body mentioned in Function 1 above. Except for the type character, if no other keyword modification is added, the default is a local variable. For example, the following code:

void test1 (void)

{

unsigned char a;

static unsigned char b;

…

a++;

b++;

}

In this example, variable a is a local variable, and variable b is a local static variable. Function one illustrates the characteristics of the local static variable b: in the function body, a variable declared as static (that is, a local static variable) maintains its value during the function call. What does this sentence mean? If the above function test1 is called twice in succession:

void main (void)

{

…

test1();

test1();

…

}

Then pause the program and read the values ​​of a and b. You will find that a=1 and b=2. What's going on, every time the test1 function is called, the local variable a will be re-initialized to 0x00; then a++ is executed; and the local static variable can maintain its value during the call.

Usually use this feature to count the number of times a function is called.

Declare a local variable of the function and set it to static type as a counter, so that the function can be counted every time the function is called. This is the best way to count the number of times a function is called, because this variable is closely related to the function, and the function may be called in many different places, so it is difficult to count from the caller's perspective. The code is as follows: void count(); int main(){ int i; for (i = 1; i

{count();

{return 0;}void count(){ static num = 0; num++; printf(" I have been called %d",num,"times/n");}

The output is: I have been called 1 times. I have been called 2 times. I have been called 3 times.

Take a look at the detailed characteristics of local static variables and note their scope.

1) Location in memory: static storage area

2) Initialization: Uninitialized global static variables will be automatically initialized to 0 by the program (the value of the automatic object is arbitrary unless it is initialized by display)

3) Scope: The scope is still a local scope. When the function or statement block that defines it ends, the scope ends.

Note: When static is used to modify local variables, it changes the storage location of local variables from the original stack to a static storage area. However, after leaving the scope, the local static variable is not destroyed, but it still resides in memory until the end of the program, but we can no longer access him.

Function 2: In the module (but outside the function), a variable declared as static can be accessed by the function used in the module, but not by other functions outside the module. It is a local global variable.

Variables defined in this way are also called global static variables: by adding the keyword static before the global variable, the global variable is defined as a global static variable. That is, the static variables declared in the module (but outside the function) mentioned in the second role above.

The benefits of defining global static variables:

It will not be accessed and modified by other files and is a local local variable.

Variables with the same name can be used in other files without conflict.

The detailed characteristics of global variables, pay attention to the scope, can be compared with local static variables:

1) Location in memory: static storage area (static storage area exists throughout the entire program run)

2) Initialization: Uninitialized global static variables will be automatically initialized to 0 by the program (the value of the automatic object is arbitrary unless it is initialized by display)

3) Scope: Global static variables are not visible outside of the file that declares him. Accurately speaking from the definition to the end of the file.

When static is used to modify a global variable, it changes the scope of the global variable (not visible outside the file that declared it), but it does not change its storage location, or it is still in the static storage area.

Effect three: Within a module, a function declared as static can only be called by other functions within this module. That is, this function is restricted to the local scope of the module that declares it.

The function defined in this way also becomes a static function: by adding the keyword static before the return type of the function, the function is defined as a static function. Function definitions and declarations are extern by default, but static functions are only visible in the file in which they are declared and cannot be used by other files.

The benefits of defining static functions:

Functions with the same name can be defined in other files without conflict

Static functions cannot be used by other files. It defines a local function.

Here I have always emphasized the localization of data and functions, which has great benefits for the structure and even optimization of the program. The greater role is that localized data and functions can pass a lot of useful information to people and can constrain data and functions. Scope of action. The private and public data/functions that are very important in C++++ objects and classes are actually extensions of local and global data/functions, which also reflects the advantages of localized data/functions from the side.

Finally, let me talk about storage specifiers. In the standard C language, storage specifiers have the following categories:

auto, register, extern and static

Corresponding to two storage periods: automatic storage period and static storage period. auto and register correspond to the automatic storage period. A variable with an automatic storage period is created when you enter the program block that declares the variable, it exists when the program block is active, and is revoked when you exit the program block.

The keywords extern and static are used to describe variables and functions with static storage periods. Local variables declared with static have a static storage duration, or static extent. Although his value remains valid between function calls, the visibility of its name is still limited to its local domain. Static local objects are initialized for the first time when the program executes to the object's declaration.

2. The const keyword

The const keyword is also a keyword often used in an excellent program. The purpose of the keyword const is to convey very useful information to those who read your code. In fact, the declaration of a parameter as a constant is to tell the user the application purpose of this parameter. By giving the optimizer some additional information, using the keyword const may produce more compact code. Reasonable use of the keyword const can make the compiler naturally protect those parameters that do not want to be changed from unintentional code modification. In short, this can reduce the occurrence of bugs.

To understand the const keyword in depth, you must know:

a. The variable modified by the const keyword can be considered as a read-only attribute, but it is never equal to a constant. The following code:

const int i=5;

int j=0;

...

i=j; //Illegal, resulting in a compilation error because it can only be read

j=i; //legal

b. Variables modified by the const keyword must be initialized when they are declared. The following code:

const int i=5; //legal

const int j; //Illegal, causing compilation error

c. Although the variable declared with const increases the allocated space, it can ensure type safety. const was originally changed from C++, it can replace define to define constants. In the old version (before the standard) of c, if you want to create a constant, you must use a preprocessor: #define PI 3.14159

No matter where PI is used, it will be replaced by 3.14159 by the preprocessor. The compiler does not perform type checking on PI, which means that you can create macros without restrictions and use it to substitute values. If you use them carelessly, errors may be introduced by preprocessing. These errors are often difficult to find. Moreover, we can not get the address of PI (that is, we cannot pass pointers and references to PI). The emergence of const solves the above problems better.

d. In the C standard, constants defined by const are global.

e. I must understand the meaning of the following statement. I remembered it repeatedly for a long time. The method is: if you want to define a pointer to a read-only attribute, then the keyword const should be placed after the *.

char *const cp; //The pointer cannot be changed, but the content pointed to can be changed

char const *pc1; //The pointer can be changed, but the content pointed to cannot be changed

const char *pc2; // Same as above (the last two statements are equivalent)

f. Declare the incoming parameters of the function as const, to indicate that the use of such parameters is only for efficiency reasons, not that the calling function can modify the value of the object.

The parameter const is usually used when the parameter is a pointer or reference, and can only modify the input parameter; if the input parameter uses the "value transfer" method, because the function will automatically generate a temporary variable for copying the parameter, the parameter does not need to be protected , So no const modification. example:

void fun0(const int * a );

void fun1(const int & a);

When calling a function, initialize the const constant with the corresponding variable, then in the function body, the part modified by const is constantized. If the formal parameter is const int * a, the content pointed by the passed pointer cannot be performed. Changes protect the content pointed to by the original pointer; if the formal parameter is const int & a, the reference object passed in cannot be changed, and the properties of the original object are protected.

g. Decorate the return value of the function to prevent users from modifying the return value. (Generally not used in embedded C, mainly used for C++)

h. const eliminates the adverse effects of preprocessor value substitution, and provides a good type check form and security, using const as much as possible where possible is of great help to our programming, provided that: you Have a sufficient understanding of const.

Finally, give two commonly used standard C library function declarations, they are all examples of using const.

1. String copy function: char *strcpy (char *strDest, const char *strSrc);

2. Return string length function: int strlen (const char *str);

3. The volatile keyword

A variable defined as volatile means that the variable may be changed unexpectedly, so that the compiler will not assume the value of the variable. To be precise, the optimizer must carefully re-read the value of this variable every time it uses this variable, instead of using the backup stored in the register.

Because the speed of accessing the register is faster than that of RAM, the compiler generally optimizes to reduce access to external RAM. such as:

static int i=0; int main(void) {... while (1) {if (i) dosomething();}} /* Interrupt service routine. */ void ISR_2(void) {i=1;} Procedure The original intention is to call the dosomething function in main when the ISR_2 interrupt is generated. However, since the compiler judges that i has not been modified in the main function, it may only perform a read operation from i to a register, and then each time if Judgment only uses the "i copy" in this register, resulting in dosomething never being called. If the variable is modified with volatile, the compiler guarantees that the read and write operations on this variable will not be optimized (definitely executed). In this example, i should also be so explained. Generally speaking, volatile is used in the following places: 1. Variables modified by the interrupt service program for detection by other programs need to be added with volatile; 2. Flags shared between tasks in a multitasking environment should be added with volatile; 3. Memory The mapped hardware register usually also need to add volatile instructions, because each time it reads and writes to it may have a different meaning;

Not understanding volatile content will bring disaster, which is also a key factor in distinguishing C language and embedded C language programmers. To emphasize the importance of volatile, let's analyze again with examples:

Code one:

int a,b,c;

a = inword(0x100);

b=a;

a=inword(0x100)

c=a;

Code two:

volatile int a;

int a,b,c;

//Read the content of 0x100 port in I/O space

a = inword(0x100);

b=a;

a=inword(0x100)

c=a;

In the above example, code one will be optimized by most compilers to the following code:

a=inword(0x100)

b=a;

c=a;

This is obviously not consistent with the purpose of the writer.There will be a missed reading of 0x100 ports in the I/O space.If volatile is added, as shown in code 2, the optimizer will not optimize any code.

From the above, the volatile keyword will reduce compiler optimization, but it guarantees the correctness of the program, so the use of the keyword volatile in suitable places is a test of programming skills.

4.struct and typedef keywords

When facing a person's large C/C++ program, we can evaluate the programming experience of its writer only by looking at the use of struct. Because a large-scale C/C++ program, it is necessary to involve some (or even a large number of) data combination structures, which can combine data that originally meant to belong to a whole. To a certain extent, will struct be used? How to use struct is a sign to distinguish whether a developer has rich development experience.

In C/C++ programming of network protocols, communication control, and embedded systems, what we often want to transmit is not a simple byte stream (char type array), but a whole of multiple data combined, and its representation form is a Structure.

Inexperienced developers often store all the content that needs to be transferred in a char array in order, and transmit network messages and other information through the pointer offset method. Doing so is complicated and error-prone, and once the control method and communication protocol change, the program must be modified very carefully.

usage:

To define a struct type in C, use typedef: typedef struct Student{ int a;}Stu; so when declaring variables: Stu stu1; if there is no typedef, you must use struct Student stu1; to declare the actual Stu here The above is the alias of struct Student. In addition, there is no need to write Student (therefore, struct Student stu1; too) typedef struct{ int a;}Stu;

One of the main functions of the struct keyword is that it can encapsulate data.It is similar to C++ objects.It can objectify some decentralized features, which provides great convenience when writing some complex programs.

For example, to write a menu program, you need to know the menu index number of the menu at this level, the number of items on the screen, the index of the menu item corresponding to the first item, the content of the menu text, the index of the submenu, and the function operations performed by the current menu. . If you operate the above items alone, the complexity of the program will be unimaginable. If the number of menu layers is smaller, it is easy to implement. Once the menu layer exceeds four layers, uh~ I can't describe it. If you have a friend who has written a menu program, you may have a deep understanding. At this time, the structure struct began to show its power:

//Structure definition

typedef struct

{

unsigned char CurrentPanel;//The menu index number of this level of menu

unsigned char ItemStartDisplay; //Display the index of the menu item corresponding to the first item

unsigned char FocusLine; //The focus is the number of items on the screen

}Menu_Statestruct;

typedef struct

{

unsigned char *MenuTxt; //menu text content

unsigned char MenuChildID;//Submenu index

void (*CurrentOperate)();//Function operation performed by the current menu

}MenuItemStruct;

typedef struct

{

MenuItemStruct *MenuPanelItem;

unsigned char MenuItemCount;

}MenuPanelStruct;

Here I refer to the structure definition in the menu program written by my brother Gong. This menu program can be up to 256 levels of menu. Before I wrote a menu program, I didn't know much about structures, nor did I think of using structures. It's just a separate processing of layers of menus: if the key is pressed, it is judged which key is pressed, the subroutine of the corresponding key is called, and the screen is displayed. In this way, each layer must be judged by the current cursor line, whether the calculation is on the top layer of the display screen, the bottom layer of the display layer, whether it is necessary to turn pages, etc., which is very tedious. Later, when I searched for information on the Internet, I found this program written by my brother. At first I didn't know that he wrote it. When I saw the source program, I saw the author's signature: China Chuanhui TranSmart. It took a day to read the code and transplant to realize that the structure has such a magical effect. When the above three structures are defined, the structure of the menu program becomes much simpler immediately, and the idea is very clear.

Hybrid IP65 Solar Power Inverter

Shenzhen Jiesai Electric Co.,Ltd , https://www.gootuenergy.com