Cómo utilizar define en lenguaje C
Uso de definir en lenguaje C (2009-08-17 19:21:11) Etiqueta de reimpresión: Charla miscelánea
definir es un comando de preprocesamiento en lenguaje C, que se utiliza para La definición de macros puede mejorar la legibilidad del código fuente y proporcionar comodidad para la programación.
Los comandos de preprocesamiento comienzan con "#", como el comando de inclusión #include, el comando de definición de macro #define, etc. Generalmente colocadas delante del archivo fuente, se denominan partes de preprocesamiento.
El llamado preprocesamiento se refiere al trabajo realizado antes de la compilación. El preprocesamiento es una función importante del lenguaje C, que lo completa el preprocesador. Al compilar un archivo fuente, el sistema hará referencia automáticamente al programa de preprocesamiento para procesar la parte de preprocesamiento del programa fuente. Una vez completado el procesamiento, ingresará automáticamente a la compilación del programa fuente.
Definición de macro
En el programa fuente en lenguaje C o C, se permite que un identificador represente una cadena, lo que se denomina "macro". Un identificador definido como "macro" se denomina "nombre de macro". Durante la compilación y el preprocesamiento, todos los "nombres de macro" que aparecen en el programa se reemplazan con las cadenas en la definición de macro. Esto se denomina "sustitución de macro" o "expansión de macro". La definición de macro se completa con el comando de definición de macro en el programa fuente. La sustitución de macros la realiza automáticamente el preprocesador.
En lenguaje C o C, la "macro" se divide en dos tipos: con parámetros y sin parámetros.
Definición de macro sin parámetros
Macro sin parámetros significa que no hay parámetros. La forma general de su definición es:
#define cadena de identificador
" Identificador" es el nombre de la macro definida. "Cadena" puede ser una constante, expresión, cadena de formato, etc.
Por ejemplo:
#define PI 3.14
Su función es especificar el identificador PI en lugar de la constante 3.14. Al escribir el programa fuente, todos los lugares donde se usa 3.14 pueden ser reemplazados por PI. Al compilar el programa fuente, el preprocesador primero realizará la sustitución de macros, es decir, usará 3.14 para reemplazar todos los nombres de macros PI y luego procederá a compilar.
La definición de macro utiliza el nombre de la macro para representar una cadena. Cuando la macro se expande, la cadena reemplaza el nombre de la macro. Esto es solo una simple sustitución. La cadena puede ser una constante o una expresión. El preprocesador no realiza ninguna comprobación sobre él. Si hay errores, sólo se pueden encontrar al compilar el programa fuente ampliado con macros.
La definición de macro no es una descripción o declaración (es una instrucción de preprocesamiento. No es necesario agregar un punto y coma al final de la línea). reemplazado.
Aquí hay un ejemplo de cómo reemplazar una constante con una macro sin parámetros:
#define PI 3.14
#include lt;stdio.hgt;
int main()
{
float r = 1.0
área flotante = PI*r*r
printf( "El área del círculo es f", área);
return 0;
}
Otro ejemplo del uso de una macro sin parámetros para reemplazar una cadena:
#define M (y*y 3*y)
#include lt;stdio.hgt;
int main() p>
{
int s, y
printf("ingrese un número: "); y);
s = 3*M 4*M 5*M
printf("s=d\n",
retorno 0;
}
# definir M (y*y 3*y) Definir expresión M (y*y 3*y). Al escribir el programa fuente, todo (y*y 3*y) se puede reemplazar por M. Al compilar el programa fuente, el preprocesador primero realizará una sustitución macro, es decir, usará (y*y 3*y) Expresión para reemplazar todos los nombres de macro M, y luego compilar.
En el programa de ejemplo anterior, primero se define la macro, se define la expresión M (y*y 3*y) y la llamada de la macro se realiza en s= 3*M 4*M 5* METRO. Después de la expansión macro durante el preprocesamiento, la declaración se convierte en: s=3*(y*y 3*y) 4* (y*y 3*y) 5* (y*y 3*y); Habrá menos paréntesis en ambos lados de la expresión (y*y 3*y) en la definición de macro. De lo contrario se producirá un error.
Definición de macros con parámetros
El lenguaje C permite que las macros tengan parámetros. Los parámetros en la definición de macro se denominan parámetros formales y los parámetros en la llamada de macro se denominan parámetros reales. Para las macros con parámetros, durante la llamada, no solo se debe expandir la macro, sino que también se deben usar los parámetros reales para reemplazar los parámetros formales.
La forma general de definición de macro con parámetros es:
#define cadena de nombre de macro (lista de parámetros formales)
La cadena contiene cada parámetro formal.
La forma general de llamada de macro con parámetros es:
Nombre de macro (lista de parámetros real)
Por ejemplo:
#define M( y) y*y 3*y
....
k=M(5);
....
Al llamar a la macro, use el parámetro real 5 para reemplazar el parámetro formal y. La declaración después de la expansión de la macro de preprocesamiento es:
k=5*5 3*5
Da un ejemplo Ejemplo específico:
#define MAX(a,b) (agt;b)?a:b
#include lt;stdio.hgt;
int main()
{
int x, y, max;
printf("ingrese dos números: "
);scanf ("dd",amp;x,amp;y);
max = MAX(x,y);
printf("max=d\n" ,max);
return 0;
}
La primera línea del programa de ejemplo anterior define una macro con parámetros, utilizando el nombre de macro MAX para representar. la expresión condicional (agt; b )?a:b, los parámetros formales a y b aparecen todos en la expresión condicional. En la séptima línea del programa, max = MAX(x, y) es una llamada de macro. Los parámetros reales xey reemplazarán los parámetros formales ay b. Después de la expansión macro, la declaración es: max = (xgt; y)?x: y se utiliza para calcular números grandes en xey;
En cuanto a la definición de macro con parámetros, es necesario explicar las siguientes cuestiones:
1. En la definición de macro con parámetros, no debe haber espacios entre el nombre de la macro y el lista de parámetros formales.
Por ejemplo, escribir: #define MAX(a,b) (agt;b)?a:b como: #define MAX (a,b) (agt;b)?a:b será considerado Es una definición de macro sin parámetros. ¿El nombre de macro MAX representa la cadena (a, b) (agt; b)?
Cuando se expande la macro, la declaración de llamada de la macro: max = MAX(x, y) se convertirá en: max = (a, b)(agt; b)?a: b(x, y); ); Esto obviamente está mal.
2. Los parámetros formales en la definición de macro son identificadores, mientras que los parámetros reales en la llamada de macro pueden ser expresiones.
#define SQ(y) (y)*(y)
#include lt;stdio.hgt;
int main()
{
int a, sq;
printf("ingrese un número: ");
scanf("d", amp; a) ;
sq=SQ(a 1);
printf("sq=d\n",sq);
devuelve 0;
}
En el ejemplo anterior, la primera línea es una definición de macro y el parámetro formal es y. El parámetro real en la llamada de macro en la séptima línea del programa es un 1, que es una expresión. Cuando se expande la macro, use un 1 para reemplazar y, y luego use (y)*(y) para reemplazar SQ. y obtenga la siguiente declaración: sq=(a 1)*(a 1); Esto es diferente de llamar a una función. Cuando se llama a una función, el valor de la expresión del parámetro real debe calcularse y luego asignarse al parámetro formal. En la sustitución de macros, la expresión del parámetro real se sustituye directamente tal como está sin cálculo.
3. En las definiciones de macros, los parámetros formales dentro de las cadenas suelen estar entre paréntesis para evitar errores. En la definición de macro del ejemplo anterior, y de la expresión (y)*(y) está entre paréntesis y el resultado es correcto.
Si elimina los paréntesis, cambie el programa a la siguiente forma:
#define SQ(y) y*y
#include lt stdio.hgt; p>int main()
{
int a, sq;
printf("ingrese un número:
); scanf(" d", amp; a);
sq=SQ(a 1);
printf("sq=d\n",
);return 0;
}
El resultado de la ejecución es: ingrese un número: 3
sq=7 (el resultado que esperábamos es 16).
¿Cuál es el problema? Esto se debe a que la sustitución solo realiza la sustitución de símbolos sin ningún otro procesamiento. Después de la macro sustitución, se obtendrá la siguiente declaración: sq=a 1*a 1; dado que a es 3, el valor de sq es 7. Obviamente, esto va en contra del significado de la pregunta, por lo que los paréntesis a ambos lados de los parámetros son indispensables. A veces, incluso agregar paréntesis alrededor de los parámetros no es suficiente, consulte el siguiente programa:
#define SQ(y) (y)*(y)
#include stdio; .hgt;
int main()
{
int a, sq;
printf("ingrese un número: ") ;
scanf("d",amp; a);
sq=160/SQ(a 1);
printf("sq=d\ n", sq);
return 0;
}
En comparación con el ejemplo anterior, este programa solo cambia la declaración de llamada de macro a: sq=160 / SQ(a 1); Al ejecutar este programa, si el valor de entrada sigue siendo 3, esperamos que el resultado sea 10. Pero los resultados reales de la ejecución son los siguientes: ingrese un número: 3 sq=160.
¿Por qué obtenemos este resultado? Al analizar la declaración de llamada de macro, después de la sustitución de la macro, se convierte en: sq=160/(a 1)*(a 1); Los operadores / " y "*" tienen la misma precedencia y asociatividad, así que primero haga 160/(3 1) para obtener 40, luego haga 40*(3 1) y finalmente obtenga 160. Para obtener la respuesta correcta, se deben agregar corchetes a toda la cadena en la definición de macro. El programa se modifica de la siguiente manera:
#define SQ(y) ((y)*(y))
# incluir lt; stdio.hgt;
int main()
{
int a,
printf("ingrese un número: ");
scanf("d", amp;
sq=160/SQ(a 1); p>
printf(" sq=d\n", sq);
return 0
}
La discusión anterior muestra que para macro En las definiciones, el seguro no solo debe usarse en Los paréntesis deben colocarse alrededor de los parámetros y también alrededor de toda la cadena.
4. Las macros con parámetros son muy similares a las funciones con parámetros, pero son esencialmente diferentes. Los resultados de procesar la misma expresión con una función y usar una macro pueden ser diferentes.
Aquí hay un ejemplo para comparar:
Usar función:
#include lt; stdio.hgt; );
int main()
{
int i=1;
while(ilt;=5)
printf("d\n", SQ(i ));
devuelve 0
}
int SQ(int y)
{
return((y)*(y));
}
Usar macro:
#define SQ(y) ((y)*(y))
#include lt;stdio.hgt;
int main()
{
int i=1;
while(ilt;=5)
printf("d\n", SQ(i));
return 0;
}
En el ejemplo de uso de una función, el nombre de la función es SQ, el parámetro formal es Y y la expresión del cuerpo de la función es ((y). )*(y) ). En el ejemplo de uso de macros, el nombre de la macro es SQ, el parámetro formal también es y y la expresión de cadena es (y)*(y)). Los dos ejemplos son idénticos en la superficie. La llamada a la función es SQ (i), la llamada a la macro es SQ (i) y los parámetros reales también son los mismos. Pero los resultados de salida son bastante diferentes. El análisis es el siguiente:
En el ejemplo de uso de una función, la llamada a la función consiste en pasar el valor del parámetro real i al parámetro formal y y luego incrementarlo. por 1. Luego genere el valor de la función. Por lo tanto, es necesario ciclarlo 5 veces. Genera el valor al cuadrado de 1 a 5. En el ejemplo del uso de macros, solo se realiza la sustitución cuando se llama a la macro. SQ(i) se reemplaza por ((i)*(i)). En el primer ciclo, dado que i es igual a 1, el proceso de cálculo es: el valor inicial de la i anterior en la expresión es 1, y luego i aumenta en 1 y se convierte en 2, por lo que el valor inicial de la segunda i en la La expresión es 2. El resultado de multiplicar los dos también es 2, y luego el valor de i aumenta en 1 para obtener 3. En el segundo ciclo, el valor de i tiene un valor inicial de 3, por lo que la i anterior en la expresión es 3, la siguiente i es 4, el producto es 12 y luego i aumenta en 1 para convertirse en 5. Al ingresar al tercer ciclo, dado que el valor de i ya es 5, este será el último ciclo. El valor de la expresión calculada es 5*6 que es igual a 30. El valor de i aumenta en 1 y se convierte en 6. La condición del bucle ya no se cumple y el bucle se detiene. Del análisis anterior, podemos ver que las llamadas a funciones y las llamadas a macros son similares en forma pero de naturaleza completamente diferente.
"\", "#", "#@" y "##"
Cuando se define con #define, la barra ("\") se utiliza para continuar la línea Sí, "#" se utiliza para convertir parámetros en cadenas agregando comillas dobles a los parámetros. "##" se usa para conectar los dos parámetros antes y después y convertirlos en una cadena. "#@" es agregar comillas simples a los parámetros. El siguiente ejemplo le facilitará la comprensión.
#define Conn(x,y) x##y
#define ToChar(a) #@a
#define ToString(x) #x
int n = Conn(123, 456); El resultado es n=123456;
char* str = Conn("asdf", "adf") El resultado es str = " asdfadf" ;
char a = ToChar(1); el resultado es a='1';
char* str = ToString(123132); se convierte en str="123132" ;
¿Por qué necesitamos los tres operadores "#", "#@" y "##"? Los motivos son los siguientes:
Si el nombre de la macro está entre comillas en el programa fuente, el preprocesador no realizará la sustitución de macros en él. De la siguiente manera:
#define OK 100
#include lt; stdio.hgt;
int main()
{ p >
printf("OK");
printf("\n");
devuelve 0; p >En el ejemplo anterior, el nombre de la macro OK se define para representar 100, pero OK está entre comillas en la instrucción printf, por lo que no se realiza la sustitución de macros. El resultado de ejecución del programa es: OK, lo que significa que "OK" se trata como una cadena.
De manera similar, si el nombre de la macro está entre comillas simples en el programa fuente, el preprocesador no realizará la sustitución de macros en él.
Anidamiento de definiciones de macros
Las definiciones de macros permiten el anidamiento y los nombres de macros ya definidos se pueden utilizar en la cadena de definición de macros. El preprocesador lo reemplaza capa por capa durante la expansión macro. Por ejemplo:
#define PI 3.1415926
#define S PI*y*y
Declaración correspondiente: printf("f", s); p >
Después de la sustitución de la macro, se convierte en: printf("f", 3.1415926*y*y);
Conclusión
Utilice una macro para reemplazar una utilizada con frecuencia en el programa Constante, de modo que cuando la constante cambia, no es necesario modificar todo el programa, solo se puede modificar la cadena definida por la macro, y cuando la constante es relativamente larga, podemos usar identificadores más cortos y significativos para escribir el programa , que es más conveniente para algunos. Para dar un ejemplo familiar, pi es un valor comúnmente usado en matemáticas. A veces usamos 3.14 para representarlo, y otras veces usamos 3.1415926, etc. Esto depende de la precisión requerida para el cálculo si compilamos un programa. varias veces, debe determinar un valor que no cambiará durante esta ejecución. Sin embargo, es posible que más adelante descubra que la precisión del programa ha cambiado y necesita cambiar su valor. Esto requiere modificar todos los valores relevantes. en el programa Esto nos traerá algunos inconvenientes, pero si usamos una definición de macro y usamos un identificador en su lugar, solo podemos modificar la definición de macro al modificar. También puede reducir la necesidad de ingresar un valor largo como 3.1415926 varias veces. Podemos hacer esto Definir #define pi 3.1415926, que reduce la entrada y es fácil de modificar.
Además, el uso de definiciones de macros con parámetros puede completar la función de las llamadas a funciones, reducir la sobrecarga del sistema y mejorar la eficiencia operativa.
Como se menciona en el lenguaje C, el uso de funciones puede hacer que el programa sea más modular, más fácil de organizar y reutilizable. Sin embargo, cuando ocurre una llamada a una función, la escena donde se llama a la función debe conservarse para que la subfunción. puede regresar para continuar la ejecución después de la ejecución. De manera similar, se necesita una cierta cantidad de tiempo para restaurar la escena donde se llamó a la función después de que se ejecuta la subfunción. Si la subfunción realiza muchas operaciones, esta sobrecarga de tiempo de conversión se puede ignorar. , pero si la subfunción completa menos funciones, puede incluso Si solo se completa una operación, como la operación de una declaración de multiplicación, esta parte de la sobrecarga de conversión será relativamente grande. Sin embargo, este problema no ocurrirá cuando se use. una definición de macro con parámetros, porque realiza la expansión de macro en la etapa de preprocesamiento. No se requiere conversión en el momento de la ejecución, es decir, se ejecuta localmente. Las definiciones de macros pueden completar operaciones simples, pero las operaciones complejas aún deben completarse mediante llamadas a funciones, y el espacio de código de destino ocupado por las definiciones de macros es relativamente grande. Por lo tanto, al usarlo, debe decidir si desea utilizar una definición de macro de acuerdo con la situación específica.