Mi informacion de contacto
Correo[email protected]
2024-07-12
한어Русский языкEnglishFrançaisIndonesianSanskrit日本語DeutschPortuguêsΕλληνικάespañolItalianoSuomalainenLatina
en el último número[Lenguaje C] - Explicación detallada del preprocesamiento (Parte 2) Durante el estudio, presentamos en detalle el conocimiento relevante de las macros en el preprocesamiento. Creo que todos ganarán mucho. No se preocupe, sigamos aprendiendo otros conocimientos sobre el preprocesamiento en este número.
# 运算符
Convierte un argumento de una macro en una cadena literal.Se permite aparecer en la lista de sustitución de macros con parámetros.# 运算符
La operación realizada puede entenderse como "stringificación".
¿Qué significa eso?
Primero hagamos un presagio:
int mian()
{
printf("hello" "worldn");
printf("helloworldn");
return 0;
}
¿Cuál es la diferencia entre las dos líneas de código anteriores? Echemos un vistazo juntos:
Como puede ver, el efecto de dos cuerdas y una cuerda es el mismo.C语言会把两个字符串天然连成一个字符串
, agregar un espacio en el medio es inútil.
Ahora hay una escena como esta:
int main()
{
int a = 1;
printf("The value of a is %dn", a);
int b = 20;
printf("The value of b is %dn", b);
float f = 8.5f;
printf("The value of f is %fn", f);
return 0;
}
Descubrimos que la lógica de las tres líneas de código es muy相像
Si, pero hay些许不同
。
Entonces pensamos que, dado que son tan similares, ¿podríamos ponerlos?封装成一个函数
, para facilitar su uso?
Pero las funciones no pueden realizar esta función.
entonces ¿qué debemos hacer?
Podemos intentar usar macros para solucionarlo.
#define Print(n, format) printf("The value of n is " format "n", n)
int main()
{
int a = 1;
Print(a, "%d");
//printf("The value of a is %dn", a);
int b = 20;
Print(b, "%d");
//printf("The value of b is %dn", b);
float f = 8.5f;
Print(f, "%f");
//printf("The value of f is %fn", f);
return 0;
}
resultado de la operación:
descubrimos nnnorteorteorteorteorteorteorte No ha cambiado, entonces, ¿cómo debo modificarlo?
Aquí es donde se debe utilizar nuestro operador #:# Convierte un argumento de una macro enliteral de cadena,Ahora mismo nnnorteorteorteorteorteorteorte convertirse “ n ” “n”“norteorteorteorteorteorteorte”
En este momento, podemos usar el método de empalme para convertirnos
#define Print(n, format) printf("The value of " #n " is " format "n", n)
no lo sabes?Lo entenderás después de leer la explicación a continuación.
##
se puede ubicar en élLos símbolos de ambos lados se combinan en un solo símbolo., que permite la definición de macros.从分离的文本片段创建标识符
。##
se llamamarcar pegado .Tal conexión debe producir una合法
indicador; de lo contrario, el resultado no estará definido.
Hemos dicho antes que para escribir una función que encuentre el valor mayor de dos números, es necesario escribir diferentes funciones para diferentes tipos de datos.
int int_max(int x, int y)
{
return x > y ? x : y;
}
float float_max(float x, float y)
{
return x > y ? x : y;
}
Esto es inevitablemente demasiado engorroso y existen muchas similitudes entre las dos funciones.
¿Hay alguna forma de crear rápidamente dicha función?como una funciónMohoIgual, solo aplica una función y saldrá
Podemos escribir uno como este.宏
:
#define GENERIC_MAX(type)
type type##_max(type x, type y)
{
return x > y ? x : y;
}
#define GENERIC_MAX(type)
type type##_max(type x, type y)
{
return x > y ? x : y;
}
GENERIC_MAX(int); //相当于定义了一个函数int_max
GENERIC_MAX(float); //相当于定义了一个函数float_max
int main()
{
int r1 = int_max(3, 5);
printf("%dn", r1);
float r2 = float_max(2.3f, 7.6f);
printf("%fn", r2);
return 0;
}
resultado de la operación:
También podemos CCG CCGgramoC.C. Observar los resultados preprocesados en el entorno..i
archivo, tener una comprensión más intuitiva de
Por supuesto, la función generada de esta manera también es incómoda de depurar.
Entonces aquí ##
¿Qué papel juega?
agregar ##
, el compilador pensará que son un símbolo
Echemos un vistazo a Kanga.##
Efecto:
En términos generales, la sintaxis para usar funciones y macros es muy similar, por lo que语言本身没法帮我们区分二者
Uno de nuestros hábitos habituales es:
- Nombra la macrotodas las mayúsculas
- Nombre de la funciónNo utilices todas las mayúsculas
Por supuesto, estas reglas de nomenclatura no son absolutas.
Por ejemplo compensar compensaroadjsía Esta macro está escrita en minúsculas.
Nota: compensar compensaroadjsía Se utiliza para calcular el desplazamiento de los miembros de la estructura con respecto a la posición inicial de la estructura.
# indefinido indefinidotúnorteorteorteorteorteorteortedmiF Las instrucciones se utilizan paraEliminar una definición de macro
El código anterior se utiliza en la línea 169.# indefinido indefinidotúnorteorteorteorteorteorteortedmiF Macro eliminada MAX.No hay ningún problema al llamar a las líneas 168 antes de la eliminación, pero se informará un error al llamar a las líneas 170 después de la eliminación.
Muchos compiladores de C (sin incluir VS) brindan la capacidad de definir símbolos en la línea de comando.Se utiliza para iniciar el proceso de compilación.
Por ejemplo : Esta característica es útil cuando queremos compilar diferentes versiones de un programa basadas en el mismo archivo fuente. (Supongamos que se declara una matriz de cierta longitud en un programa. Si la memoria de la máquina es limitada, necesitamos una matriz muy pequeña, pero si la memoria de otra máquina es más grande, la matriz que necesitamos puede ser más grande)
La definición de la línea de comando está enetapa de preprocesamientoProcesado, en la etapa de preprocesamiento, en el código anterior tamaño tamañotal Se ha determinado el valor de
Al compilar un programa, es muy difícil compilar o abandonar uno (un grupo de declaraciones).方便
de.porque podemos usardirectiva de compilación condicional
La instrucción de compilación condicional es este código.我想让你编译就编译,不想让你编译你就不要编译了
. Podemos establecer una condición para él. Si la condición es verdadera, este código se compilará. Si la condición es falsa, este código no se compilará.
Por ejemplo:
Sería una lástima eliminar algún código de depuración, pero sería un obstáculo para conservarlo, de modo que podamos compilarlo selectivamente.
Instrucciones de compilación condicional de uso común:
#if 常量表达式
//···
#endif
#if 常量表达式
//···
#elif 常量表达式
//···
#else
//···
#endif
Cual enunciado es verdadero, ese enunciado se ejecuta
#define M 1
int main()
{
#if M == 0
printf("hellon");
#elif M == 1
printf("worldn");
#elif M == 2
printf("csdnn");
#endif
printf("886n");
return 0;
}
#if defined(symbol)
#ifdef symbol
//上面两个的反面
if !defined(symbol)
#ifndef symbol
#if defined(OS_UNIX)
#ifdef OPTION1
unix_version_option1();
#endif
#ifdef OPTION2
unix_version_option2();
#endif
#elif defined(OS_MSDOS)
#ifdef OPTION2
msdos_version_option2();
#endif
#endif
# include "filename"
Estrategia de búsqueda: primero enEl directorio del proyecto donde se encuentran los archivos fuente.Si no se encuentra el archivo de encabezado, el compilador buscará el archivo de encabezado de la función de biblioteca de la misma manera.Búsqueda de ubicación estándararchivo principal
Si no puedes encontrarlo de nuevoError de compilación
Linux Linuxyoenux La ruta del archivo de encabezado estándar del entorno (donde se coloca el archivo de encabezado):
/usr/include
Ruta de archivo de encabezado estándar para el entorno VS:
C:Program Files (x86)Microsoft Visual Studio 12.0VCinclude
//这是VS2013的默认路径
#include <filename.h>
Busque el archivo de encabezado y vaya directamente aruta estándarVaya y busque, y si no puede encontrarlo, recibirá un mensaje.Error de compilación。
¿Significa esto que también se puede utilizar para archivos de biblioteca?“ ”
El formulario contiene
la respuesta esafirmarSí, pero la búsqueda se hace de esta manera.menos eficientePor supuesto, este también es el caso.no es fácil de distinguir¿Es un archivo de biblioteca o un archivo local?
Después de estudiar lo anterior (compilación y vinculación), sabemos que el archivo de encabezado se incluye en la etapa de preprocesamiento.直接将该文件的代码拷贝到包含头文件的地方
Si un archivo de encabezado se incluye 10 veces, en realidad se compila 10 veces. Si se incluye repetidamente, la presión sobre la compilación será mayor.
prueba . c prueba.caesa.C
#include "test.h"
#include "test.h"
#include "test.h"
#include "test.h"
#include "test.h"
int main()
{
return 0;
}
prueba . h prueba.haesa.yo
void test();
struct Stu
{
int id;
char name[20];
};
Pero en un proyecto, un archivo inevitablemente se incluirá varias veces, entonces, ¿cómo resolver este problema?
Respuesta:compilación condicional
#ifndef __TEST_H__
#define __TEST_H__
//头文件的内容
#endif
¿Cómo entenderlo?
- Al incluir el archivo de encabezado por primera vez, ¿debería compilarse?juez primero
- El símbolo __TEST_H__ no esno definida,desearcompilar
- Inmediatamente despuésDefinir el símbolo __TEST_H__
- Luego incluya el archivo de encabezado nuevamente y busque __TEST_H__ha sido definido,no másPara el archivo de encabezado incluido más adelante, realicecompilar
Sin embargo, la forma de escribir anterior es más problemática. Hay otra forma de escribir:
#pragma once
El efecto es el mismo que el método anterior.
Esto evita la introducción repetida de archivos de encabezado.
#error
#pragma
#line
···
#pragma pack()//在结构体部分介绍
Amigos interesados pueden leer "Anatomía en profundidad del lenguaje C"
Bien, ese es todo el conocimiento sobre el preprocesamiento en este número. Espero que este blog pueda resultarle útil. Al mismo tiempo, corríjame si hay algún error y ¡progresemos juntos en el camino del aprendizaje del lenguaje C!