Definición de macro de lenguaje C

1. Pretratamiento

  El primer paso para compilar un programa en lenguaje C es la etapa de preprocesamiento, esta etapa es la etapa donde entra en juego la macro. El preprocesador de C realiza algunas operaciones textuales en el código fuente antes de compilarlo. Las tareas principales incluyen eliminar comentarios, insertar el contenido del archivo que está # incluido, definir y reemplazar los símbolos definidos por #define y determinar si parte del código se basa en condiciones Compile (#if) para compilar. La operación de "naturaleza textual" se refiere a reemplazar un párrafo de texto por otro párrafo sin considerar ningún contenido semántico. Macro es solo una herramienta de reemplazo de texto en la etapa de preprocesamiento de C, y es invisible para el código binario después de la compilación

2. Uso de la definición de macro

① Macro constante

  El uso más común de #define es usar #define para definir una constante simbólica. Cuando quieras modificarla, solo necesitas modificar la declaración #define y no necesitas modificar todos los códigos.
Ejemplo:

#include"stdio.h"
#define PI 3.14
#define STR "圆周率约等于"
int main()
{
    
    
	printf("%s %f",STR,PI); //预处理时会被替换为 printf("%s %f","圆周率约等于",3.14);
	return 0;
}

 
  
  

resultado de la operación:
Inserte la descripción de la imagen aquí


② Declaración macro

  También podemos definir una o más declaraciones con macros.
Ejemplo:

#include"stdio.h"
#define Print printf("hello world!")
int main()
{
     
     
	Print;  //预处理时会被替换为 printf("hello world!");
	return 0;
}

  
   
   

Resultado de la operación:
Inserte la descripción de la imagen aquí

③Función macro

  También puedo usar macros para definir funciones, porque las definiciones de macros también pueden tomar parámetros.
Ejemplo:

#include"stdio.h"
#define Print(str) printf("%s",str)
int main()
{
     
     
	Print("这是一个只有一条语句的宏函数!");
    //预处理时会被替换为 printf("%s","这是一个只有一条语句的宏函数!")
	return 0;
}

  
   
   

Inserte la descripción de la imagen aquí

④Otros

1. #undef se usa para deshacer la definición de macro, el uso es el siguiente:

#define PI 3.141592654

...

// código
# undef PI
// PI no es válido desde el principio

2. Utilice ifndef para evitar que los archivos de encabezado se incluyan y compilen repetidamente

  Este es un tipo de definición de macro, que se puede usar para la selección de rama según se haya definido una variable, generalmente se usa para depurar, etc. De hecho, deben ser exactamente las tres funciones de preprocesamiento (definición de macro, inclusión de archivo y Conditional compilación): compilación condicional. Cuando el lenguaje C compila el programa, primero "preprocesará" de acuerdo con el comando de preprocesamiento. El sistema de compilación en lenguaje C incluye preprocesamiento, compilación y vinculación.

#ifndef x //先测试x是否被宏定义过
#define x //如果没有宏定义下面就宏定义x并编译下面的语句
...
...
...
#endif //如果已经定义了则编译#endif后面的语句

 
  
  

El indicador de condición #ifndef comprueba si la constante precompilada ha sido definida anteriormente por la macro. Si no está definido por una macro antes, el valor del indicador de condición es verdadero, por lo que todas las declaraciones de #ifndef a #endif se incluyen para el procesamiento de compilación. Por el contrario, si el valor del indicador #ifndef es falso, se ignorará la línea entre este y el indicador #endif. El propósito principal del indicador condicional #ifndef es evitar la inclusión y compilación repetidas de archivos de encabezado.
  No ignore el #ifndef en el encabezado, esto es algo muy crítico. Por ejemplo, tiene dos archivos C, los cuales incluyen el mismo archivo de encabezado. Al compilar, estos dos archivos C deben compilarse juntos en un archivo ejecutable, por lo que surge el problema, muchos conflictos de declaración.

Así que ponga el contenido del archivo de encabezado en #ifndef y #endif. Independientemente de si varios archivos hacen referencia a su archivo de encabezado, debe agregar esto. El formato general es este:

  #ifndef <标识>

# define <identificación>

. . . . . .

# endif

En teoría, la <Identificación> se puede nombrar libremente, pero la "identificación" de cada archivo de encabezado debe ser única. La regla de nomenclatura del logotipo es generalmente que el nombre del archivo de encabezado está todo en mayúsculas, seguido de guiones bajos, y el "." En el nombre del archivo también está subrayado, como: stdio.h


  #ifndef _STDIO_H_

# define STDIO_H

. . . . . .

<span class="token macro property">#<span class="token directive keyword">endif</span></span>

#ifndef xxx // Si xxx no está definido
#define xxx // define xxx
#endif // Fin Si
este uso es principalmente en el archivo de encabezado, es principalmente para evitar la inclusión repetida de la clase, así que agregue el frente antes del encabezado archivo de la clase Dos, reemplace xxx con el nombre de la clase y agregue la última oración al final


Tres. Funciones relacionadas con la definición de macros

①Ruptura de línea "\"

  Cuando definimos una instrucción macro o una función macro, es imposible tener siempre una instrucción. ¿Qué pasa si hay muchas declaraciones? ¿Están todas escritas en una línea? Obviamente el código no es hermoso y la legibilidad no es buena, por lo que hay declaraciones múltiples Cuando, agregamos "\" al final de cada línea (excepto en la última línea), que representa el significado
del salto de línea. Ejemplo:

#include"stdio.h"
#define Print   printf("这是第1条语句\n");\
 		    	printf("这是第2条语句\n");\
 		    	printf("这是第3条语句\n")

# define Show (str1, str2, str3)
{ printf ("% s \ n", str1); printf ("% s \ n", str2); printf ("% s \ n", str3); \



}
int main ( )
{
Print ; // Función macro sin parámetros
Show ( "primero" , "segundo" , "tercero" ) ; // Función macro con parámetros
return 0 ;
}

Resultado de la operación:
Inserte la descripción de la imagen aquí

②Carácter de cadena "#"

  "#" significa "cadena de caracteres". El # que aparecerá en la definición de macro convierte el siguiente parámetro en una cadena.
Ejemplo:

#include"stdio.h"
#define Print(str)\
{\
	printf(#str"的值是%d",str);\	
}
int main()
{
    
    
	int x=3,y=4;
	Print(x+y); //此处等价于printf("x+y""的值是%d",x+y);
	            //#str等价于"x+y",所以#str不需要再用双引号引起来 
	return 0;
}

 
  
  

Resultado de la operación:
Inserte la descripción de la imagen aquí


③ Conector de fragmento "##"

  "##" es una forma de separar y conectar, su función es separar primero y luego forzar la conexión. En las definiciones de macros ordinarias, el preprocesador generalmente interpreta los espacios como marcas de segmento, compara cada segmento con el anterior y reemplaza los mismos. Pero el resultado de esto es que hay algunos espacios entre los segmentos reemplazados. Si no queremos estos espacios, podemos agregar algunos ## para reemplazar los espacios.
ejemplo:

#include"stdio.h"
#define Add(n,value)\
{\
	num##n+=value;\
 } 
int main()
{
    
    
	int num1=1;
	int num2=10;
	Add(2,10); //等价于num2+=10; 这里把num和2连接成了num2 
	printf(" num1=%d\n num2=%d",num1,num2); 
	return 0;
}

 
  
  

4. Uso inteligente de la función macro

①Transferencia de tipo

  Sabemos que aunque las funciones pueden pasar parámetros, no pueden pasar tipos como parámetros. A veces necesitamos usar plantillas STL para lograr la reutilización de funciones, pero tenemos otra opción en este momento, que es escribir funciones macro.
Ejemplo:
Una función para abrir la memoria.

#define Malloc(type,size) (type*)malloc(sizeof(type)*size)

 
  
  

En este momento, solo podemos abrir varios tipos de memoria pasando el tipo y la capacidad como parámetros.

int *p=Malloc(int,100); //开辟int类型的内存
char *q=Malloc(char,100); //开辟字符类型的内存

 
  
  

② Pase la matriz

  Cuando una matriz se pasa como un parámetro de función, perderá sus características de matriz, es decir, la función sizeof () no se puede usar para calcular el tamaño de la matriz Por ejemplo, cuando escribimos una función de clasificación, no solo necesitamos saber la primera dirección de la matriz al ordenar, pero también necesita saber la matriz El tamaño de la matriz, pero cuando el nombre de la matriz se pasa como parámetro, no se puede conocer el tamaño de la matriz. En este momento, nuestra función debe pasar el segundo parámetro, que es el tamaño de la matriz, por lo que la función debe escribirse como Ordenar (int * a, int tamaño). Pero la función macro puede resolver este problema.
Ejemplo:
Lo siguiente usa una función macro para escribir un algoritmo de ordenación por inserción

#include"stdio.h"
#define InsertSort(list)\
{\
	int s=sizeof(list)/4;\
	int i,j;\
	for(i=2;i<=s;i++)\
	{\
		list[0]=list[i];\
		for(j=i-1;list[j]>list[0];j--)\
				list[j+1]=list[j];\	
		list[j+1]=list[0];\		
	}\ 
}
int main()
{
    
    
	int num[]={
    
    0,2,5,7,3,1,8,0,8,22,57,56,74,18,99,34,31,55,41,12,9,4};
	InsertSort(num);
	for(int i=1;i<sizeof(num)/4;i++)	
		printf("%d ",num[i]);
	return 0;
} 

 
  
  

Resultado de la operación: por
Inserte la descripción de la imagen aquí
supuesto, hay muchos usos inteligentes de las definiciones de macro, no todos se enumeran aquí

Cinco. Asuntos que necesitan atención

① El problema de la precedencia de los operadores

#define MULTIPLY(x, y) x * y

 
  
  
  • 1

  Esta es una función de multiplicación muy simple. Al calcular MULTIPLY (10, 10), el resultado es 100, todo el mundo lo sabe, pero cuando calcula MULTIPLY (5 + 5, 10), ¿cree que el resultado sigue siendo 100? Por supuesto no, MULTIPLY (5 + 5, 10) = 5 + 5 * 10 = 55, por lo que el resultado es 55, por lo que debemos prestar especial atención a la prioridad de los operadores al escribir funciones macro. Una forma más segura de escribir aquí debe escribirse Me gusta esto

#define MULTIPLY(x, y) ((x)*(y))

 
  
  

② Llamada repetida de macro parámetros

#define MAX(a,b) ((a)>(b)?(a):(b))
int a=0;
int b =1;
int c =MAX(++a,++b);

 
  
  

Mucha gente aquí piensa que c = MAX (1,2) = 2; de hecho, el código anterior es equivalente a

int c =((++a)>(++b)?(++a):(++b));

 
  
  

Se puede ver que, de hecho, ab se suma dos veces, entonces c = 1> 2? 2: 3 = 3, entonces el resultado es 3.

③El problema de tragar punto y coma

#include"stdio.h"
#define FUN(n)\
{\
	while(n>0)\
	{\
		if(n==3)\
			break;\	
	}\	
}
int main()
{
    
    
	int num=10;
	if(num>0)
		FUN(num);
	else
		num=-num;
	return 0;
}

 
  
  

  Parece que no hay ningún problema con el código, pero se informa un error tan pronto como se compila. El compilador muestra "error: 'else' sin un 'si' previo". Resulta que la función FUN es un bloque de código , y luego if (num> 0) FUN (num); Es equivalente a if (num> 0) {…}; ¿No es esto solo poner un punto y coma después de las llaves? Entonces, por supuesto, el else carece de if. En
  este time, podemos usar do {…} while (0) para resolver esta Pregunta, está bien escribir lo siguiente, porque se necesita un punto y coma después de while ()

#define FUN(n)\ 
do\
{
    
    \
	while(n>0)\
	{
    
    \
		if(n==3)\
			break;\	
	}\	
}while(0)

 
  
  

④ Problema de llamadas recursivas

#define NUM (4 + NUM)

 
  
  

  De acuerdo con el entendimiento anterior, (4 + NUM) se expandirá a (4 + (4 + NUM)), y luego se expandirá hasta que se agote la memoria. Sin embargo, la estrategia adoptada por el preprocesador es expandirse solo una vez. En otras palabras, NUM solo se expandirá a (4 + NUM), y el significado de NUM después de la expansión se determinará de acuerdo con el contexto.

⑤ Preprocesamiento de macroparámetros

  Si el parámetro de macro contiene otra macro, entonces el parámetro de macro se expandirá completamente antes de ser sustituido en el cuerpo de la macro, a menos que el cuerpo de la macro contenga # o ##.

Existen las siguientes definiciones de macro:

#define A(y) X_##y
#define B(y) A(y)
#define SIZE 1024
#define S SIZE

 
  
  

A (S) se expandirá a X_S. Como el cuerpo de la macro contiene ##, los parámetros de la macro se sustituyen directamente en el cuerpo de la macro.
B (S) se ampliará a X_1024. Debido a que el cuerpo de macro de B (S) es A (S), no hay # o ##, por lo que S se expandirá por completo a 1024 antes de ser sustituido y luego sustituido en el cuerpo de macro, convirtiéndose en X_1024.

Supongo que te gusta

Origin blog.csdn.net/qq_44378854/article/details/109298352
Recomendado
Clasificación