- Makefile
1.1 Estructura:
objetivos: requisitos previos
dominio
1.2 compilación gcc: -g, -o, -c, -D, -w, -W, -Wall, -O3
-c: los archivos fuente se compilan y ensamblan, pero no se vinculan
Ejemplo:
gcc -c prueba.cpp -o prueba
-c seguido de varios archivos fuente
Cuando -c va seguido de varios archivos de origen, se generará un archivo .o para cada archivo de origen, pero -o no se puede usar en este momento .
Enlace de referencia: Introducción a las opciones de compilación de gcc -o y -c_gcc -o_chengqiuming's Blog-CSDN Blog
1.3 Variables de automatización
variable de automatización |
ilustrar |
ps |
Indica el archivo de objeto |
ps |
Cuando el archivo de destino es un archivo de biblioteca estática, representa un nombre de miembro de la biblioteca estática. |
$< |
Indica el primer archivo dependiente. |
$^ |
Representa todos los archivos dependientes. |
ps |
Una lista de todos los archivos dependientes más nuevos que el archivo de destino. |
$+ |
Como "$^", pero conserva las ocurrencias duplicadas de archivos dependientes. Se utiliza principalmente en la ocasión de referencia cruzada de la biblioteca cuando el programa está vinculado. |
ps |
En reglas de patrones y reglas de patrones estáticos, significa "tallo". El "tallo" es la parte representada por el "%" en el patrón de destino (cuando un directorio está presente en el nombre del archivo, |
prueba: prueba.o prueba1.o prueba2.o
gcc -o $@ $^
prueba.o:prueba.c prueba.h
gcc -o $@ $<
prueba1.o:prueba1.c prueba1.h
gcc -o $@ $<
prueba2.o:prueba2.c prueba2.h
gcc -o $@ $<
Agregar los caracteres "D" o "F" a estas variables en GNU crea una serie de variables de automatización de variantes que pueden operar en los nombres de los archivos.
D representa la parte del directorio y F representa la parte del archivo. Tales como: $(@D), $(@F)
1.4 Búsqueda de archivos de objetos
4.1 VPATH
VPATH := src coche
prueba:prueba.o
gcc -o $@ $^
Primero se buscan los archivos en el directorio src y luego se buscan los archivos en el directorio car.
4.2 vpath
vpath test.c src coche
Busque archivos test.c en dos rutas
1.5 objetivos falsos
limpio:
rm -rf *.o prueba
dos, la concha
Enlace de referencia: https://www.jianshu.com/p/74e8739ddc01
script de shell 2.1,
#!/bin/bash
echo "¡HolaMundo!"
2.2 Declaración de control de flujo
si – entonces – si no – fi
si no
si elif fi
en bucle
mientras declaración
hasta bucle (opuesto a la condición while)
caso... esac
-eq/-ne/-gt/-ge/-lt/le
mayor o igual mayor o igual
-e verdadero si el archivo existe
-r True si el archivo existe y es legible
-w True si el archivo existe y se puede escribir
-x True si el archivo existe y es ejecutable
-s True si el archivo existe y tiene al menos un carácter
-d verdadero si el archivo es un directorio
-f verdadero si el archivo existe y es un archivo normal
-c verdadero si el archivo existe y es un archivo especial de caracteres
-b True si el archivo existe y es un archivo especial de bloque
2.3 Funciones
Ejemplo:
#!/bin/bash
función vecesDiversión(){
echo " Esta función multiplicará dos números "
echo " Por favor ingrese el primer número "
leer num1
echo " Por favor ingrese el segundo número "
leer num2
devolver $(( ${num1} * ${num2} ))
}
tiemposdivertidos
echo -n " ¿ El valor de multiplicación de los dos números ingresados es $?"
3. Puntero
En comparación con otros lenguajes de programación de alto nivel, el lenguaje C puede operar el hardware de la computadora de manera más eficiente, y las instrucciones de operación del hardware de la computadora dependen en gran medida de las direcciones.
Los punteros proporcionan una forma de operar en las direcciones, por lo tanto, el uso de punteros puede permitir que el lenguaje C opere de manera más eficiente en el hardware subyacente de la computadora. Además, las matrices se pueden manipular de manera más conveniente a través de punteros. En cierto sentido, se puede decir que el puntero es la esencia del lenguaje C.
3.1 Memoria y dirección
Enlace de referencia: http://c.biancheng.net/c/pointer/
(1) &: Obtener dirección variable
(2) Definición de variable de puntero: como int *p;
(3) puntero "salvaje"
int *pi,a; //pi no está inicializado, no tiene puntero legal y es un puntero "salvaje"
*pi=3; // ¡ Error de tiempo de ejecución! La operación de almacenamiento no se puede realizar en el espacio señalado por el puntero "comodín". Esta declaración intenta almacenar 3 en el espacio aleatorio al que apunta el puntero pi "salvaje" y se producirá un error de tiempo de ejecución
(4) Punteros y matrices
Puntero de matriz: ejemplo int (*p)[5]; puede representar una matriz bidimensional
#definir M 3
#definir N 4
int a[M][N],i,j;
int (*p)[N]=a; // equivalente a dos sentencias int (*p)[N] ; p=a;
Matriz de punteros: ejemplo int * a[5];
int a0,a1,a2,a3,a4;
a[0]=&a0;
a[1]=&a1;
...
a[4]=&a4;
3.2 Punteros de función
Enlace de referencia: https://blog.csdn.net/Jacky_Feng/article/details/108953519
(1) Definición de puntero de función
Si se define una función en el programa, al compilar, el compilador asignará una sección de espacio de almacenamiento para el código de la función, y la dirección inicial de este espacio (también conocida como la dirección de entrada) se denomina puntero de esta función.
Ejemplo:
int func(int a,int b);// declaración de función
int (*p) (int , int );// Defina una lista de parámetros como dos variables de tipo int , y el tipo de valor devuelto es un puntero de función p de tipo int
p=func ; // El puntero de función p apunta a la dirección inicial de la función func
(2) Aplicación de punteros de función
Llame a la función a la que apunta el puntero de función p
( *p ) (3, 5);
3.3 Función de devolución de llamada
El programa pasa el puntero de función de esta función a otras funciones a través de parámetros, y llamar a este puntero de función en esa función es equivalente a llamar a esta función.Tal proceso se llama devolución de llamada, y la función llamada se llama función de devolución de llamada.
Ejemplo:
#incluir <iostream>
utilizando el espacio de nombres estándar;
// 1. Definir la función de devolución de llamada
impresión vacía (int n)
{
para (int i = 0; i < n; i++) {
cout << "hola mundo" << endl;
}
}
// 2. Definir el prototipo de función de devolución de llamada (puntero de función)
typedef void (*CallbackFun)(int);
// 3. Definir la función de devolución de llamada de registro
void registCallback(CallbackFun callback,int n)
{
devolución de llamada (n);
}
int principal()
{
// 4. Pase el puntero de la función de impresión como un parámetro a la función de registro registerCallback para llamar a la devolución de llamada , es decir, se ejecuta la función de impresión .
registrarseCallback(imprimir, 10);
}
4. Multihilo y multiprocesamiento
Para sistemas roscados:
(1) Un proceso es una unidad independiente de asignación de recursos
(2) Thread es una unidad independiente de programación de recursos
Para sistemas sin rosca:
(1) Un proceso es una unidad independiente de programación y asignación de recursos
4.1 Métodos de comunicación entre procesos y sus ventajas y desventajas
Tubería (TUBO )
(1) Tubería conocida: un método de comunicación semidúplex que permite la comunicación entre procesos no relacionados.
①Ventajas: Se puede realizar la comunicación entre procesos de cualquier relación.
②Desventajas: a. Almacenamiento a largo plazo en el sistema, el uso inadecuado es propenso a errores; b. Búfer limitado.
(2) Tubería sin nombre: un método de comunicación semidúplex que solo se puede usar entre procesos con parentesco (proceso padre-hijo).
①Ventajas: Simple y conveniente.
② Desventajas: a. Limitado a la comunicación unidireccional, b. Solo se puede crear entre su proceso y sus procesos relacionados, c. El búfer es limitado.
Semáforo (Semaphore): Un contador que se puede utilizar para controlar el acceso a los recursos compartidos por varios subprocesos.
- Pros: Puede sincronizar procesos.
② Desventajas: semáforo limitado.
Signal (Señal ): Un método de comunicación más complejo que se utiliza para notificar al proceso de recepción que se ha producido un evento.
Message Queue (Cola de Mensajes ): Es una lista enlazada de mensajes, almacenados en el kernel e identificados por un identificador de cola de mensajes.
- Ventajas: puede realizar la comunicación entre cualquier proceso y realizar la sincronización entre el envío y la recepción de mensajes a través de la función de llamada al sistema, sin considerar el problema de sincronización, lo cual es conveniente.
② Desventajas: La copia de información requiere tiempo adicional de CPU, lo que no es adecuado para ocasiones con gran cantidad de información u operaciones frecuentes.
Memoria compartida (Shared Memory ): mapea una sección de memoria a la que otros procesos pueden acceder. Esta memoria compartida es creada por un proceso, pero múltiples procesos pueden acceder a ella.
- Ventajas: sin necesidad de copiar, rápido, gran cantidad de información.
② Desventajas: a. La comunicación se logra conectando directamente el búfer de espacio compartido al espacio de direcciones virtuales del proceso, por lo que la sincronización de las operaciones de lectura y escritura entre procesos; b. Usando el búfer de memoria para intercambiar información directamente, la entidad del memoria Existe en la computadora y solo puede ser compartida por muchos procesos en el mismo sistema informático, lo cual es un inconveniente para la comunicación en red.
Socket (Socket ): se puede utilizar para la comunicación de procesos entre diferentes computadoras
①Ventajas:
a. Los datos de transmisión están a nivel de byte, los datos de transmisión se pueden personalizar, el volumen de datos es pequeño y la eficiencia es alta;
B. Corto tiempo de transmisión de datos y alto rendimiento;
C. Adecuado para la interacción de información en tiempo real entre el cliente y el servidor;
D. Se puede cifrar y la seguridad de los datos es fuerte;
② Desventajas: los datos transmitidos deben analizarse y convertirse en datos de nivel de aplicación.
4.2 Métodos de comunicación entre hilos
4.2.1 Mecanismo de bloqueo
Incluye mutex/cantidad (mutex), bloqueo de lector-escritor (bloqueo de lector-escritor), bloqueo de giro (bloqueo de giro), variable de condición (condición)
- Mutex/Volume (mutex): proporciona métodos para evitar que las estructuras de datos se modifiquen simultáneamente de manera exclusiva.
El mecanismo mutex incluye principalmente las siguientes funciones básicas:
- Inicialización de exclusión mutua: pthread_mutex_init()
- Bloqueo mutex: pthread_mutex_lock()
- Bloqueo de juicio mutex: pthread_mutex_trylock()
- Bloqueo mutex: pthread_mutex_unlock()
- Eliminar mutex: pthread_mutex_destroy()
- Bloqueo de lector-escritor (reader-writer lock): permite que varios subprocesos lean datos compartidos al mismo tiempo, mientras que la operación de escritura se excluye mutuamente.
El mecanismo de bloqueo de lectura y escritura incluye principalmente las siguientes funciones básicas:
- int pthread_rwlock_init(pthread_rwlock_t * rwlock, const pthread_rwlockattr_t * attr);
- int pthread_rwlock_destroy(pthread_rwlock_t *rwlock);
- int pthread_rwlock_rdlock(pthread_rwlock_t *rwlock);
- int pthread_rwlock_tryrdlock(pthread_rwlock_t *rwlock);
- int pthread_mutex_timedrdlock(pthread_rwlock_t * rwlock,const struct timespec * tsptr);
- int pthread_rwlock_wrlock(pthread_rwlock_t *rwlock);
- int pthread_rwlock_trywrlock(pthread_rwlock_t *rwlock);
- int pthread_mutex_timedwrlock(pthread_rwlock_t * rwlock,const struct timespec * tsptr);
- int pthread_rwlock_unlock(pthread_rwlock_t *rwlock);
- Un bloqueo de giro (spin lock) es similar a un mutex, tanto para proteger los recursos compartidos. El mutex es cuando el recurso está ocupado y el solicitante entra en el estado de suspensión, mientras que el bloqueo giratorio realiza un bucle para verificar si el titular ha liberado el bloqueo.
El mecanismo spinlock incluye principalmente las siguientes funciones básicas:
- int pthread_spin_destroy(pthread_spinlock_t *bloqueo);
- int pthread_spin_init(pthread_spinlock_t *bloqueo, int pshared);
- int pthread_spin_lock(pthread_spinlock_t *bloqueo);
- int pthread_spin_trylock(pthread_spinlock_t *bloqueo);
- int pthread_spin_unlock(pthread_spinlock_t *bloqueo);
- Variable de condición (condición): Un proceso puede bloquearse atómicamente hasta que cierta condición sea verdadera. La prueba de la condición se realiza bajo la protección de un mutex. Las variables de condición siempre se usan con mutexes.
Los semáforos multiproceso incluyen las siguientes funciones básicas.
- int sem_init(sem_t *sem, int pshared, int val sin firmar);
- int sem_espera(sem_t *sem);
- int sem_post(sem_t *sem);
- int sem_destory(sem_t *sem);
4.2.2 Mecanismo de semáforo (Semaphore)
(1) Semáforo de hilo sin nombre
(2) Semáforo de subproceso con nombre
Mecanismo de señal (Signal): similar al procesamiento de señales entre procesos
Barrera: una barrera permite que cada subproceso espere hasta que todos los subprocesos cooperantes hayan llegado a un punto determinado y luego continúe la ejecución desde ese punto.
El propósito de la comunicación entre subprocesos es principalmente para la sincronización de subprocesos, por lo que los subprocesos no tienen un mecanismo de comunicación para el intercambio de datos como la comunicación de procesos.
Recursos privados y compartidos entre procesos
Privado: espacio de direcciones, montón, variables globales, pila, registros
Compartido: segmento de código, datos públicos, directorio de procesos, ID de proceso
Recursos privados y compartidos entre hilos
Privado: pila de subprocesos, registros, contador de programa
Compartido: montón, espacio de direcciones, variables globales, variables estáticas
4.3 Comparación, pros y contras y elección entre multiproceso y multihilo
1. Contraste
2. Ventajas y desventajas
3. Seleccione
(1) Subprocesos prioritarios que deben crearse y destruirse con frecuencia
(2) Uso prioritario de subprocesos que requieren una gran cantidad de cálculos
(3) El procesamiento fuertemente relacionado usa subprocesos y el procesamiento débilmente relacionado usa procesos
(4) Puede extenderse para usar procesos para la distribución de múltiples máquinas y usar subprocesos para la distribución de múltiples núcleos
(5) Cuando se cumplan todos los requisitos, utilice el método con el que esté más familiarizado y mejor en
Cinco, programación de red Linux
5.1 TCP
5.1.1 Modelo de red TCP
Para crear un servidor tcp bajo Linux , hay seis pasos de la siguiente manera:
socket - crea un socket
bind - enlazar host y puerto
listen - establecer el enchufe de escucha
accept - acepta conexiones de clientes y genera nuevos sockets
leer/escribir – enviar y recibir datos
cerrar - cerrar el zócalo
La creación de un cliente se divide principalmente en los siguientes pasos:
socket -- crear un socket
connect -- Conéctese activamente al servidor
escribir/leer: enviar y recibir datos
cerrar - cerrar el zócalo
- socket - crea un socket
Prototipo de función: socket int (dominio int, tipo int, protocolo int);
Descripción de parámetros:
dominio: familia de protocolos, especifique la familia de protocolos utilizada para la comunicación; las opciones comunes son las siguientes:
AF_UNIX, AF_LOCAL : Comunicación local , utilizada para la comunicación entre procesos / hilos locales;
AF_INET:Protocolos de Internet IPv4
AF_INET6:Protocolos de Internet IPv6
tipo: tipo de enchufe, las opciones comúnmente utilizadas son las siguientes:
SOCK_STREAM: socket de flujo, correspondiente únicamente a TCP;
SOCK_DGRAM: socket de datagrama, correspondiente únicamente a UDP;
SOCK_RAW: socket crudo (transparente);
protocolo: generalmente complete 0, este parámetro es obligatorio cuando el tipo de tipo es SOCK_RAW.
Valor devuelto: socket (descriptor de archivo) se devuelve en caso de éxito y -1 en caso de error.
- bind - enlazar host y puerto
Prototipo de función: int bind(int sockfd, const struct sockaddr *addr, socklen_t addrlen);
Estructura general de la dirección:
estructura sockaddr {
sa_family_t sa_family; //dirección de la familia
char en_datos[14];
}
Estructura de la dirección de Internet:
estructura sockaddr_in {
u_short sin_family; // familia de direcciones, AF_INET, 2 bytes
u_short sin_port; // puerto, 2 bytes
estructura in_addr sin_addr; // IPV4地址,4 bytes
char sin_zero[8]; // 8 bytes sin usar, como relleno
};
Estructura de la dirección IPv4
// dirección de Internet
estructura in_addr
{
in_addr_t s_addr; // dirección de red u32
};
Estructura de dirección del protocolo de comunicación local: se puede utilizar para la comunicación entre procesos
estructura sockaddr_un
{
sa_family_t sun_family; //familia de protocolos
char sun_path[108]; // ruta del archivo de socket
}
- listen - establecer el enchufe de escucha
Parámetros: sockfd --- descriptor de archivo de socket
backlog --- monitorear la longitud de la cola
- accept - acepta conexiones de clientes y genera nuevos sockets
int accept(int sockfd, struct sockaddr *addr, socklen_t *addrlen);
parámetro:
sockfd --- descriptor de archivo de socket
addr --- IP del cliente y número de puerto
addrlen --- longitud de la dirección del cliente
Nota: addr y addrlen se utilizan para obtener la dirección del cliente, si no necesita conocer el cliente, estos dos parámetros se establecen en NULL
- conectar: conectarse activamente al servidor (cliente)
int connect(int sockfd, const struct sockaddr *addr, socklen_t addrlen);
parámetro:
sockfd --- descriptor de archivo de socket
addr --- dirección del servidor
addrlen --- longitud de addr
- leer/escribir – enviar y recibir datos
ssize_t send(int sockfd, const void *buf, size_t len, int flags);
parámetro:
sockfd --- descriptor de archivo de socket
buf --- la primera dirección de los datos enviados
len --- número de bytes enviados
banderas --- método de envío(0)
size_t recv(int sockfd, void *buf, size_t len, int flags);
Parámetros: sockfd --- descriptor de archivo de socket
buf --- La primera dirección del espacio donde se almacenan los datos
len --- el número de bytes que desea recibir
banderas --- Método de recepción (0)
- cerrar - cerrar el zócalo
- función setockopt
Enlace de referencia: https://blog.csdn.net/Mr_XJC/article/details/106788694
5.2 UDP
Pasos (ver TCP para llamadas a funciones):
(1) Crear un zócalo
(2) Vincular IP y vincular puerto
(3) Enviar y recibir mensajes
Enlace de referencia: comunicación UDP en entorno Linux_linux udp communication_workingwei's blog-CSDN blog
6. Estructura de datos
Enlace de referencia: Estructura de datos del lenguaje C_Blog de Rising Sun Chuyang-CSDN Blog
La diferencia entre estructura typedef y estructura de definición de estructura
Enlace de referencia: [lenguaje C] diferencia entre typedef struct y struct use_difference between typedef struct and direct struct_Mijie's Voice Blog-CSDN Blog
La sintaxis de struct es más complicada, así que vamos a dar ejemplos uno por uno.
Ejemplo 1:
estructura{
char a;
intb;
} X;
Aquí, se crea una variable con dos miembros,
Un carácter, un entero.
Ejemplo 2:
estructura ESTUDIANTE{
nombre del personaje;
edad int;
};
Aquí, se crea una etiqueta,
Se proporcionó un nombre de ESTUDIANTE para la lista de miembros.
En el futuro, puede declarar variables a través de struct STUDENT x;
Lo siguiente es la combinación de typedef y struct
Ejemplo tres:
estructura typedef{
nombre del personaje;
edad int;
}ALUMNO;
El efecto aquí es básicamente el mismo que en el Ejemplo 2.
ESTUDIANTE ahora es el nombre de un tipo de datos.
Las declaraciones posteriores se pueden escribir directamente como ESTUDIANTE x;
Ejemplo cuatro:
estructura typedef NODO{
datos int;
estructura NODO* siguiente;
}nodo;
Esta es una forma común de crear nodos de lista enlazada, que se puede dividir en dos pasos:
primer paso
estructura NODO{
datos int;
estructura NODO* siguiente;
};
Creó un tipo de estructura llamado NODO,
El segundo paso typedef NODE node;
Nombre el tipo de datos NODO como nodo
Cabe resaltar que
Al crear una lista enlazada,
estructura typedef NODO{
datos int;
estructura NODO* siguiente;
}nodo;
El puntero se crea usando struct NODE* next;
En las funciones posteriores de creación, inserción, eliminación y búsqueda, y en la función principal,
El puntero de declaración se unifica con el puntero de nodo*;
problemas encontrados
- Al compilar con múltiples subprocesos, falta la vinculación de la biblioteca y agregue -lpthread o -pthread al compilar
如:gcc -o test.c test -lpthread
- Problema de espacio de escaneo, dos soluciones
- reemplazar fgets();
- scanf(“%[^\n]”, mensaje);