[C language] Preprocessing & keywords, often overlooked but important points

Table of contents

Foreword:

1. Pretreatment:

The role of preprocessing and commonly used commands

(1) The compilation process of C language:

(2) Commonly used preprocessing commands

The role and examples of preprocessing commands

(1) Macro definition

(2)#error

2. Keywords:

const keyword:

(1) Function

(2) Similarities and differences with precompiled instructions

static keyword:

(1) When modifying local variables:

(2) When modifying global variables:

(3) When modifying the function:

Volatile keyword:

(1) Function:

(2) Specific examples:

typedef keyword:

(1) Function

(2) The difference with #define

sizeof keyword:

(1) Function 

(2) strlen () function

extern keyword:

(1) Function   

(2) Points to note

register keyword:

(1) Function

(2) Points to note

auto keyword:

(1) Function

(2) Application scenarios


Foreword:

When we first learn embedded, we will buy a development board to get started. In the library functions we call, we will use some preprocessing commands and some keywords. These are points that we often ignore and do not use, but in fact they are It plays an important role , and these are precisely the points that the company interviewers focus on

1. Pretreatment:

The role of preprocessing and commonly used commands

(1) The compilation process of C language:

ae08295b3a6e420d9b6121ac2baecf96.pngThe role of preprocessing: header file inclusion (#include), macro replacement (#define), conditional compilation (#ifdef, #ifndef), removal of comments, and addition of line numbers.

(2) Commonly used preprocessing commands

preprocessing name significance
#define macro definition
#include Causes the compiler to embed another source file into the source file with #include
#if、#endif If the constant expression behind #if is true, compile the code between it and #endif, otherwise skip.
#else Where #if fails, #else establishes another alternative
#ifdef、#ifndef Respectively means "if defined" and "if not defined", another way of conditional compilation
#error When compiling the program, as long as # error is encountered, a compilation prompt error will be generated and the compilation will stop.

The role and examples of preprocessing commands

(1) Macro definition

Advantages : code reusability; improved performance
Disadvantages : non-debuggable (replaced in the pre-compilation stage); no type safety checks; poor readability and error-prone.

  • No-argument macro: generally used to replace any constants and strings, etc.
#define M 5                // 宏定义
#define PI 3.14            // 宏定义
int a[M];                  // 会被替换为: int a[5];
int b = M;                 // 会被替换为: int b = 5;
printf("PI = %.2f\n", PI); // 输出结果为: PI = 3.14
  • Parameter macro: It is similar to a function, but it is not a function.
    • The macro with parameters is just a simple character replacement in the compilation preprocessing stage; while the function is called and returned at runtime.
    • Macro replacement does not account for runtime, only compile time; while function calls account for runtime (allocation unit, reserved field, value passing, return).
    • Macros with parameters do not allocate memory when they are processed; function calls allocate temporary memory.
    • There is no type problem in macros, the macro name has no type, and its parameters are also typeless; while the actual parameters and formal parameters in the function must define types, and the type requirements of the two are consistent.
  • Concrete example:
//输入两个参数并返回较小的一个
//应用了三目条件运算符
#define  MIN(A, B)  ((A) <= (B) ? (A) : (B))

//已知数组table,用宏求数组元素个数
//数组元素个数 = 数组长度 / 数组元素长度
#define  COUNT(table)  (sizeof(table) / sizeof(table[0]))

Note: If *p++ is brought into the macro body, the pointer p will perform two self-increment operations. 

(2)#error

Function : When compiling the program, as long as #error is encountered, a compilation error will pop up.

Application scenario : When the program is relatively large, some macro definitions are often specified externally (such as makefile), or specified in the system header file. When you are not sure whether XXX is currently defined, you can use #error

A specific example is as follows: 

//如果遇到abc时,执行#error
#ifdef abc  
#error "abc has been defined"  
#else  
…  
#endif 

2. Keywords:

Here we focus on the important keywords that we often overlook, including:

  • Storage class: const , static , extern, register, auto
  • Data types: volatile , typedef
  • Operator: sizeof

const keyword:

(1) Function

  • A keyword that defines a read-only variable. The value of a constant type variable or object cannot be changed or updated.
  • After const modification, the program should not try to modify it.

(2) Similarities and differences with precompiled instructions

  • The same: both can be used to define constants.
  • Different: const has a data type, and the compiler can do static type checking; while macro definitions have no type, which may cause type errors

static keyword:

(1) When modifying local variables:

  • Changed its storage location, stored in the static area;
  • At the same time, its life cycle is changed for the entire source program, so it is only initialized once, and it is automatically initialized to 0 if it is not explicitly initialized.

(2) When modifying global variables:

  • Changed its scope so that it can only be accessed by functions used in the file.

(3) When modifying the function:

  • Changed its scope and can only be called by other functions in this file.

Volatile keyword:

(1) Function:

  • When encountering a variable declared with this keyword, the compiler will no longer make assumptions ( optimization ) about the code that accesses the variable, thus providing stable access to special addresses.
  • The optimizer must carefully re-read the value of the variable every time it uses a volatile-modified variable , instead of using a backup stored in a register . For example: hardware registers of parallel devices (eg: status registers)

(2) Specific examples:

Can a parameter be both const and volatile? Can a pointer be volatile? What's wrong with the function below?

int square(volatile int *ptr)   
{   
    return *ptr * *ptr;   
}   

① Yes. An example is the read-only status register, which is volatile because it may be changed unexpectedly, and const because the program should not attempt to modify it. 

②Yes. An example is when an interrupt service routine modifies a pointer to a buffer. 

③This function originally wants to obtain the square of the value pointed to by the pointer *pr, but *ptr points to a volatile parameter, and the compiler will generate code similar to the following.

int square(volatile int *ptr)   
{   
    int a, b;   
    a = *ptr;   
    b = *ptr;   
    return a * b;   
} 

typedef keyword:

(1) Function

  • In C language, it is generally used to declare a synonym for an existing data type
  • It is also possible to do preprocessing like

(2) The difference with #define

#define  dPS  struct s *   
typedef  struct s *  tPS;  
dPS  p1, p2;   
tPS  p3, p4;   
  • define is a string replacement, so dPS p1, p2; is actually written as struct s * p1, p2; that is, define p1 as a pointer to a structure, and p2 as an actual structure.
  • tPS p3, p4;; defines two pointers p3 and p4 correctly.

sizeof keyword:

(1) Function 

  • Used to calculate the number of bytes of memory occupied by variables and data types.
  •  sizeof(array name) gets the number of bytes occupied by the array. sizeof (string pointer name) gets the number of bytes occupied by the pointer.

(2) strlen () function

  • Used to test the number of bytes occupied by the string, excluding the end character '\0'.
  • strlen (character array name) gets the number of bytes occupied by the string, and strlen (string pointer name) gets the number of bytes occupied by the string.

extern keyword:

(1) Function   

  • extern comes into play during the linking phase.
  • It is used to refer to global variables across files, that is, to refer to a global variable that has been defined in other files in this file.

(2) Points to note

  • It cannot be initialized when it is referenced, such as extern var, but not extern var = 0.

register keyword:

(1) Function

  • The compiler will place register-modified variables in CPU registers as much as possible to speed up their access speed, generally used for frequently used variables

(2) Points to note

  • The register variable may not be stored in memory, so you cannot use & to get the address of the variable;
  • Only local variables and formal parameters can be used as register variables;
  • The number of registers is limited, and too many register variables cannot be defined.

auto keyword:

(1) Function

  • It is used to define automatic local variables. Automatic local variables are established when entering the statement block that declares the variable, and are canceled when exiting the statement block. They are only used inside the statement block.
  • When auto is modified, the data type can be automatically inferred.

(2) Application scenarios

  • It is used to replace the variable declaration which is long and complicated, and the scope of use of the variable is specific.
  • The i in the for loop will automatically deduce its type at compile time, without us having to explicitly define the long string.

Note: It is not recommended to use auto in this way when actually programming. It is clearer and easier to directly write the type of the variable.

Guess you like

Origin blog.csdn.net/weixin_42373086/article/details/129874871