Advanced use of embedded C language (the most detailed in the whole network)

Advanced use of embedded C language (the most detailed in the whole network)

1, Macro

Macro, in my opinion, is a major feature of C language. On this basis, some special functions can be used.

1.1 variable type parameter macro

In some application scenarios, we often need to find the maximum and minimum values similar to the two. We often encapsulate such a simple function into a method function. However, in the function syntax, we should clearly define the variable types of parameters, that is, different types of variables need to establish relatively different functions, but we use some special means, You can use macros to implement indefinite types of macros with parameters. See the following examples:

#define max(x,y)({\
	typeof(x) _x = (x);\
	typeof(y) _y = (y);\
	(void)(&_x == &_y);\
	_x > _y? _x:_y;})

Yes, such a macro with parameters can realize the function of maximizing any variable type.

  • First, let's analyze some functions of this code.

typeof: gets the variable type of a variable.

(void) (&_x = = &_y): this code is only used to remind the user whether the two variable types are consistent.

__ x > _ y? _ x:_ y;: Returns the final result.

2, Variable parameters

### 2. 1 simple use of variable parameters

We are actually familiar with variable parameters, but you may not know it yet. Do you remember the first line of code when you first started learning C language? Yes, it is

printf("hallo wolrd!")

In fact, the printf function is implemented using variable parameters. Let's take an example:

printf(char *fmt,...); 	//This is the prototype of the printf function
int count = 10;
char sex = 'L';
printf("%d,%c",count,sex);

  • fmt: format string.
  • . . . : Corresponding to multiple parameters.

To implement variable parameters, you need to add the header file stdarg h

  • va_list: actually a char * type.
  • va_start(fmt,args): obtain the address after the args parameter according to the address of the parameter args and save it in the fmt pointer variable.
  • va_end(args): release the args pointer and assign it NULL.

Let's use a classic and simple example to see the usage.

#include <stdarg.h>

void printArray(int count,...)
{
    char var;
    int gap,i;
    /*Created a pointer to the parameter*/
    va_list args;
    /*Initialization pointer*/
    va_start(args,count);
	/*The indefinite parameters are analyzed*/
    for( i = 0 ; i < count ; i++)
    {
        printf("*args %d = %d\n",count,*(int*)args);
        gap = (int)(sizeof(count)/sizeof(var));	//Gets the number of bytes that the pointer should skip
        args += gap;
    }
	/*The pointer released after use is NULL*/
    va_end(args);
}
void main(void)
{
    printArray(4,1,2,3,4);
    printArray(5,1,2,3,4,5);
}

Finally, we can see that the following parameters are printed one by one

2.2 commissioning

When we write programs, we often need to print some logs. Different things need to be printed under different circumstances, so we often have a debugging module. The following is a simple debugging module program implemented with indefinite parameters, as follows:

#include <stdarg.h>
#include <stdio.h>

/* Where users need to configure */
#define USER_DEBUG_LEVEL 3
/*
    ERROR:Error level log    
    WARNIG:Warning level log
    DEBUG:Log of mode level
*/
#if USER_DEBUG_LEVEL>=3
    #define ERROR
#endif 
#if USER_DEBUG_LEVEL >= 2
    #define WARNING
#endif 
#if USER_DEBUG_LEVEL >= 1
    #define DEBUG
#endif 

void printfError(char* fmt ,...)
{
    va_list args;
    va_start(args,fmt);
    #ifdef ERROR
        vprintf(fmt,args);
    #endif 
    va_end(args);
}
void printfWarning(char* fmt ,...)
{
    va_list args;
    va_start(args,fmt);
    #ifdef WARNING
        vprintf(fmt,args);
    #endif 
    va_end(args);
}
void printfDebug(char* fmt ,...)
{
    va_list args;
    va_start(args,fmt);
    #ifdef DEBUG
        vprintf(fmt,args);
    #endif 
    va_end(args);
}
void main(void)
{
    printfError("Error\n");
    printfWarning("Warning\n");
    printfDebug("Debug\n");
}

Different debugging levels correspond to different print data, which can be used for debugging.

3, Inline function

Inline function is to fill the contents of the function body into the place where the function is called after compilation. Instead of calling the function itself, it directly executes the statements in the function body. However, if it is declared as an inline function, it is uncertain whether it is an inline function in the end.

Let's take a simple example, as follows:

inline int sum(int a ,int b)
{
    return a + b;
}

void main(void)
{
    printf("sum = %d",sum(5,6));
}

The returned result is clear at a glance. In ordinary functions, the sum() function is called and then returned. The inline function fills a+b into the position of the function name as follows, and the action cycle of the formal parameter is in the function statement.

Inline as follows:

inline int sum(int a ,int b)
{
    return a + b;
}
void main(void)
{	
    {
       int a = 5,b = 6;
 	   printf("sum = %d",a + b);
    }
}

Where the function body itself replaces the original function call.

Pay attention to the official account, get the code of this article and some tools in debugging SCM.

Keywords: C Go

Added by kippy on Sat, 18 Dec 2021 17:12:31 +0200