C/C++ macro definition advanced usage

c/c++ macro definition advanced usage
1. ANSI standard five predefined macro names

    __LINE__ indicates the line number of the line of code
    __FILE__ indicates the file name of the
    source file __DATE__ indicates the date when the source file was compiled, format (month/day/year)
    __TIME__ indicates the time when the source file was compiled into the target code, format (hour: minute :Seconds)
    __STDC__ indicates whether the compiler is standard or not, when it is standard, it means the constant 1, and non-standard means other numbers

Test case

#include <stdio.h>
#include <stdlib.h>
 
 
#define INFO(msg) info_debug(__FILE__, __LINE__, __DATE__, __TIME__, msg)
 
void info_debug(const char* filename, int line, const char* date, const char* time, const char* msg)
{
	printf_s("info_debug %s:%d (%s-%s):%s", filename, line, date, time, msg);
}
 
int main()
{
	INFO("Hello world!\n");
	system("pause");
	return 0;
}

Define functions or such:

#define Function(name) void Func##name(void)

//使用
Function(mytest)
{
    ....
}

//编译器宏替换后
void Funcmytest(void)
{
    ...
}

2. Macro definition usage of indefinite parameters

__VA_ARGS__ means all remaining parameters

Specific usage

#define LOG(fmt, ...) log(__FILE__, __LINE__, fmt, __VA_ARGS__)

"..." means the omitted parameters, __VA_ARGS__ corresponds exactly to the function of "..."

Test case
 

#include <stdio.h>
#include <stdlib.h>
#include <stdarg.h>
 
 
#define INFO(msg) info_debug(__FILE__, __LINE__,  msg)
#define LOG(fmt, ...) log(__FILE__, __LINE__, fmt, __VA_ARGS__)
 
void info_debug(const char* filename, int line, const char* msg)
{
	printf_s("info_debug %s:%d :%s", filename, line, msg);
}
 
void log(const char* filename, int line, const char* fmt, ...)
{
	int size;
	char * msg = NULL;
	va_list args;
	va_start(args, fmt);
	size = vsnprintf(NULL, 0, fmt, args) + 1;
	msg = (char *)malloc(size);
	vsnprintf(msg, size, fmt, args);
	info_debug(filename, line, msg);
	free(msg);
	va_end(args);
}
 
int main()
{
	INFO("Hello world!\n");
	LOG("%s %d\n", "debug", 14);
	system("pause");
	return 0;
}

3. The meaning of # and ## in macro definition

The function of # is to stringify the macro parameters behind it. Simply put, after replacing the macro variable it refers to, add a double quotation mark around it

## is called a connector, used to connect two Tokens into one Token, ## is to replace the passed parameters as a string

Test case

#include <stdio.h>
#include <stdlib.h>
#include <stdarg.h>
 
 
#define INFO(msg) info_debug(__FILE__, __LINE__,  msg)
#define LOG(fmt, ...) log(__FILE__, __LINE__, fmt, __VA_ARGS__)
 
#define VERSION 1.0.0
#define __STR__(x) (#x)  
#define TO_STR(x) __STR__(x)
 
#define LINK(x, y) x##y
 
 
void info_debug(const char* filename, int line, const char* msg)
{
	printf_s("info_debug %s:%d :%s", filename, line, msg);
}
 
void log(const char* filename, int line, const char* fmt, ...)
{
	int size;
	char * msg = NULL;
	va_list args;
	va_start(args, fmt);
	size = vsnprintf(NULL, 0, fmt, args) + 1;
	msg = (char *)malloc(size);
	vsnprintf(msg, size, fmt, args);
	info_debug(filename, line, msg);
	free(msg);
	va_end(args);
}
 
int main()
{
	INFO("Hello world!\n");
	LOG("%s %d\n", "debug", 14);
	printf_s("#把一个宏定义变成字符串:version = %s\n", TO_STR(VERSION));
	int n = LINK(12, 34);
	printf_s("##把两个参数拼接一起:%d\n", n);
	system("pause");
	return 0;
}

4. Multi-line macro definition and function call in the macro definition

Example:

#define  DSPI0_RX  0
#define  DSPI1_RX  1
#define  DSPI2_RX  2
#define  DSPI3_RX  3
#define  DSPI4_RX  4

void  Spi_LLD_IsrRxDma_DSPI();

#define SPI_LLD_ISRRXDMA_DSPI_N_SRV(MCU_DMA_CHANNEL_n_SOURCE) \
if(MCU_DMA_CHANNEL_n_SOURCE == DSPI0_RX)\
{\
    Spi_LLD_IsrRxDma_DSPI();\
}\
else if(MCU_DMA_CHANNEL_n_SOURCE == DSPI1_RX)\
{\
    Spi_LLD_IsrRxDma_DSPI(); \
}\
else if(MCU_DMA_CHANNEL_n_SOURCE == DSPI2_RX)\
{\
    Spi_LLD_IsrRxDma_DSPI();\
}\
else if(MCU_DMA_CHANNEL_n_SOURCE == DSPI3_RX)\
{\
    Spi_LLD_IsrRxDma_DSPI();\
}\
else if(MCU_DMA_CHANNEL_n_SOURCE == DSPI4_RX)\
{\
    Spi_LLD_IsrRxDma_DSPI();\
}

Different functions are called according to the value of MCU_DMA_CHANNEL_n_SOURCE.

5. Null pointer definition

#define NULL_PTR ((void *)0)

6. The variable or return value macro definition specifies the type and the usage skills of the corresponding module

For example, constant variables

typedef usigned char uint8;

typedef uint8 Adc_ChannelType; 

#define CONST(consttype, memclass) const consttype

STATIC CONST(Adc_ChannelType, ADC_CONST) AdcGroup_10_Assignment_PB_2_1[4] =
{//AdcGroup_10
    0U,
    1U,
    2U,
    3U,
};

//Adc_ChannelType indicates that the array element is the ADC channel type, which is a constant variable of the ADC module.

Another example: ordinary variable declaration

 #define VAR(vartype, memclass) vartype

  VAR(Adc_ChannelType, ADC_VAR) chId;

7. Macro definition realizes assertion

for example:

#define  ASSERT(condition, message) {\

  if(!(condition)){\

  logError("Assertion failed:",#condition,message);\

  exit(EXIT_FAILURE);\

}\

}

8. In embedded development, use #define and typedef in combination to change address constants into structure variables, and use the "." operator to access structure variable members.

Examples of use

typedef volatile union
{
 struct
 {
  unsigned int ECCENLDRAM     : 1;
  unsigned int ECCENDTAG      : 1;
  unsigned int ECCENSPRAM     : 1;
  unsigned int ECCENPTAG      : 1;
  unsigned int ECCENPMU       : 1;
  unsigned int ECCENPRAM      : 1;
  unsigned int ECCENCMEM      : 1;
  unsigned int ECCENCAN       : 1;
  unsigned int ECCENERAY      : 1;
  unsigned int                : 23;
 } B;
 int I;
 unsigned int U;

} SCU_ECCCON_type;


SCU_ECCCON_type SCU_ECCCON_Test;

#define SCU_ECCCON    (*( SCU_ECCCON_type *) 0xffff10000)

#define SCU_ECCCON_Test_ECCENERAY    (SCU_ECCCON.B.ECCENERAY)

//那么直接对SCU_ECCCON_Test_ECCENERAY宏进行操作就是对结构体变量SCU_ECCCON的B成员的ECCENERAY位进行操作。

//注意该案例中的结构体为变量定义的方法。

 

Guess you like

Origin blog.csdn.net/sunlin972913894/article/details/106308349