c / c ++ definición de macro uso avanzado
1. Estándar ANSI cinco nombres de macro predefinidos
__LINE__ indica el número de línea de la línea de código
__FILE__ indica el nombre de archivo del archivo
fuente __DATE__ indica la fecha en la que se compiló el archivo fuente, formato (mes / día / año)
__TIME__ indica la hora en que se compiló el archivo fuente en el código de destino, formato (hora: minuto: segundos)
__STDC__ indica si el compilador es estándar o no, cuando es estándar, significa la constante 1, y no estándar significa otros números
Caso de prueba
#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;
}
Definir funciones o tal:
#define Function(name) void Func##name(void)
//使用
Function(mytest)
{
....
}
//编译器宏替换后
void Funcmytest(void)
{
...
}
2. Uso de definiciones macro de parámetros indefinidos
__VA_ARGS__ significa todos los parámetros restantes
Uso específico
#define LOG (fmt, ...) log (__ FILE__, __LINE__, fmt, __VA_ARGS__)
"..." significa los parámetros omitidos, __VA_ARGS__ corresponde exactamente a la función de "..."
Caso de prueba
#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. El significado de # y ## en la definición macro
La función de # es clasificar los parámetros de macro detrás de él. En pocas palabras, después de reemplazar la variable de macro a la que se refiere, agregue una comilla doble alrededor
## se llama conector, se usa para conectar dos Tokens en un Token, ## es para reemplazar los parámetros pasados como una cadena
Caso de prueba
#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. Definición de macro de varias líneas y llamada de función en la definición de macro
Ejemplo:
#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();\
}
Se llaman diferentes funciones según el valor de MCU_DMA_CHANNEL_n_SOURCE.
5. Definición de puntero nulo
#define NULL_PTR ((void *)0)
6. La definición de macro de variable o valor de retorno especifica el tipo y las habilidades de uso del módulo correspondiente.
Por ejemplo, variables constantes
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 indica que el elemento de la matriz es el tipo de canal ADC, que es una variable constante del módulo ADC.
Otro ejemplo: declaración de variable ordinaria
#define VAR(vartype, memclass) vartype
VAR(Adc_ChannelType, ADC_VAR) chId;
7. La definición macro da cuenta de la afirmación
por ejemplo:
#define ASSERT(condition, message) {\
if(!(condition)){\
logError("Assertion failed:",#condition,message);\
exit(EXIT_FAILURE);\
}\
}
8. En el desarrollo integrado, use #define y typedef en combinación para cambiar las constantes de dirección en variables de estructura, y use el operador "." Para acceder a los miembros de la variable de estructura.
Ejemplos de uso
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位进行操作。
//注意该案例中的结构体为变量定义的方法。