Embedded development plan-9-storage type, variable modifier, macro

Nineteen, storage type

  • Storage type: auto (automatic), static (static), extern (external), register (register)
  • Modifiers: const (not allowed to be modified), volatile (prevents memory from being optimized by the compiler)

19.1 auto

 Function: declare automatic type, when local variable omits storage type, it is automatic type
  1. auto cannot modify global variables
  2. Functions can only be decorated with static / extern, not auto
  3. The variable memory modified by auto is in the stack area

19.2 static

 Function: Declare static type and extend the life cycle.

static keyword modification:

  • Global variable: When static is used to modify a global variable, it limits the scope of the variable to the current file, even if other files declare global variables with the same name, they will not affect each other.
  • Local variable: When static is used to modify a local variable, it extends the life cycle of the variable, that is, the variable maintains its value during program execution, rather than being reinitialized every time the function is called. This is especially useful in recursive functions, which cannot be used across scopes.
  • Pointer: static modifying the pointer itself has no special meaning, and its behavior is no different from that of ordinary pointers. However, if static is used for the variable pointed to by the pointer, then the life cycle of the variable will be extended, similar to the effect of the above local variable. The static modified pointer cannot point to the variable address of the automatic type.
  • Function: When static is used to modify a function, it will limit the scope of the function to the current file, and other files cannot access the function, which has the function of privatization.
  • Thread-local variables (Thread-local variables):
    The C11 standard introduces the concept of thread local variables. By using the static keyword together with the keyword _Thread_local, local variables independent of threads can be created in multi-threaded programs. Each thread has its own independent variable instance, without interfering with each other.

Code sample:

  • 1. Static modified global variables
The storage type is omitted for global variables, and the default storage type is extern. The memory space of global variables is in the static area.
Generally, global variables will not be decorated with static, because the storage type of global variables is omitted, and the memory is already in the static area.

  • 2. Static modification of local variables
 Function: static modifies local variables, prolongs life cycle, not scope,
Life cycle: the look of the memory space, to release
Scope : within the valid scope of the program

  • 3. Static modification function
 Function: static modification function, so that the function declaration cycle is valid in this file, and cannot be called across files
The function omits the storage type, and the default is the extern storage type

  • 4. Static modified pointer
The static modified pointer cannot point to the variable address of the automatic type
Cause: The variable address of the automatic type is allocated after the address, and the space is allocated at the compilation stage
The variable address of the static type is allocated first, and the space is allocated when the project starts

19.3 extern

 Role: declare external storage

extern keyword declaration:

  • Global variable: When using extern to modify a global variable in a file, it indicates that the variable is a global variable defined in other files. In this way, the global variables defined by other files can be used in the current file, so as to achieve the purpose of sharing global variables among multiple files.
  • Local variables: extern should not be used for local variables, because the scope of local variables is limited to the code block in which it is defined and does not need to be accessed in other files.
  • Pointer: extern can also be used for pointers, but its effect is similar to that of global variables, indicating that the pointer is defined in other files.
  • Function: extern should not be used for functions, because the scope of the function is global, and there is no need to pass extern to access it in other files.
  1. The current global variable omits the storage type, and the default is extern
  2. The current global variable omits the storage type, and the default is extern
  3. Variables modified by extern are stored in the static area


Summary:

  • static is mainly used to limit the scope and extend the life cycle.
  • extern is mainly used to share global variables in multi-file projects.

19.4 register

 Function: declare register variables,
Variables of register type, the access speed is fast, but the address cannot be taken

Memory level: register > cache cache > main memory > auxiliary memory

19.5 const

 Function: the modified value does not change
1. The global variables modified by const are stored in the read-only segment of the static area, read-only and cannot be modified
2. Local variables modified by const are stored in the stack area and cannot be modified
3. Combination of const and pointer:
\t 
const int *p; * is on the right side of const, the value modified by const, the value cannot be changed, but the address can be changed
int const *p;* is on the right side of const, the value modified by const, the value cannot be changed, but the address can be changed
int * const p;* is on the left of const, the address modified by const, the address can be changed, but the value can be changed
const int * const p; the first const modification refers to the address of the second const modification, and neither the value nor the address can be changed
int const * const p; The first const modification refers to the address of the second const modification, and neither the value nor the address can be changed

19.6 volatile

 role: prevent memory optimization, save memory visibility

In C/C++, volatile is a keyword used to tell the compiler that the variable may be accidentally changed during program execution, thereby preventing the compiler from optimizing the variable to Ensure the correctness of the program. The main use of volatile is in the following situations:

  1. Prevent compiler optimization:
    When the compiler optimizes the code, it will minimize the reading and writing of variables to improve the execution efficiency of the program. However, the value of some variables may not be controlled by the current code segment, but changed by hardware or other concurrent threads. Using the volatile keyword tells the compiler not to optimize the variable, but to read its latest value from memory every time.

  2. Related to interrupt handling:
    In embedded systems and multithreaded environments, interrupts may modify variables in the program. If these variables are not declared as volatile, the compiler may optimize away the read operation of these variables, resulting in program errors.

  3. Interact with peripherals:
    In embedded systems, when interacting with peripherals, using the volatile keyword can ensure that access to peripheral registers is not optimized, thereby ensuring correct communication with peripherals.

Please note:volatile The keyword just tells the compiler that the variable may be modified at any time, but it does not solve all multi-threaded concurrent access problems. For the case of multi-threaded concurrency, more complex synchronization mechanisms (such as mutexes) usually need to be used. In a multi-threaded environment, the volatile keyword is only a means to ensure that the variable is not optimized, but does not guarantee thread safety.

Twenty, macro

macro: Once defined, it cannot be modified
Definition format: #define macro name macro body
Macro production replacement, no calculation, no correctness check
Macros do not belong to C statements, so do not add semicolons

20.1 Macro definition

#define M 100
#define PAI 3.14
#define CH 'A'
#define STRING "hello"
#define N
#define G =100
// The above are all macros
int main(int argc, const char *argv[])
{<!-- -->
    printf("M=%d\
",M);
    printf("PAI=%f\
",PAI);
    printf("CH=%c\
",CH);
    printf("STRING=%s\
",STRING);
// N=6; //Once the macro definition is not assigned, it cannot be assigned later
    printf("N=%d\
",N);
// printf("G=%d\
",M);

    return 0;
}

20.2 Macro function

20.2.1 Custom macro function

Definition format: #define macro function name (parameter list) macro body
#define : Define the flag of the macro, which cannot be omitted
Macro function name: meet the naming convention, generally capitalized
Parameter list: without data type
Macro body: the implemented program, without {}

Code sample:

1> Macro function with parentheses
#define SUM(x,y) x + y

#define SUM1(x,y) (x + y)

#define MIN(x,y) x>y?y:x
int main(int argc, const char *argv[])
{<!-- -->

#if N
    int a=10,b=100;
    printf("sum=%d\
",SUM(a,b)/2);//x + y/2=60

    printf("sum=%d\
",SUM1(a,b)/2);//(10 + 100)/2=55
    printf("%d",MIN(a,b));
#endif

20.2.2 System macro function

#if macro name
    C statement 1;
#else
    C statement 2;
#endif
When the macro name condition is true, execute C statement 1, otherwise execute C statement 2
#if 0 action comment

#ifdef macro name
    C statement 1;
#else
    C statement 2;
#endif
When the macro name has been defined, execute C statement 1, otherwise execute that C statement 2

#ifndef macro name
    C statement 1;
#else
    C statement 2;
#endif
When the macro name is not defined, execute that C statement 1, otherwise execute that C statement 2;

#undef macro name: cancel macro

mind map