Tabla de contenido
Este blog deducirá principalmente un subprograma de la barra de progreso que se ejecuta en Linux paso a paso, y utilizará el editor vim y el compilador gcc . Si no está familiarizado con estos dos programas, puede hacer clic en el enlace y aprender de este blog. La barra de progreso applet se muestra de la siguiente manera:
a.\r && \n
Hay muchos caracteres en el lenguaje C, pero macroscópicamente se pueden dividir en dos tipos: caracteres visibles y caracteres de control.
Caracteres visualizables: A, a, B, c... y otros caracteres
Caracteres de control: \n (retorno de carro), \t (tabulador horizontal), \r (avance de línea), etc.
\r
Aquí necesitamos usar y \n
dos caracteres bajo el sistema Linux
Generalmente, cuando usamos el lenguaje C \n
para cambiar la línea, o usamos la tecla Enter de la computadora para cambiar la línea, la cambiamos directamente a la posición más a la izquierda de la siguiente línea
int main()
{
printf("Hello\nWorld!");
return 0;
}
Pero, de hecho, estas son dos acciones, solo en la categoría de idioma. El lenguaje C usa \n
las dos acciones de cambiar a la siguiente línea y regresar a la actual más a la izquierda .
Al igual que nuestro teclado antiguo anterior, la tecla Intro es diferente de la tecla Intro actual, lo que indica que la tecla es la suma de dos acciones.
Entonces, la nueva línea a la que generalmente nos referimos se compone de estas dos acciones.
Después de comprender el conocimiento anterior, echemos un vistazo al \r
significado \n
de y
\r: retorno de carro (regresar al extremo izquierdo de la línea actual)
\n: Nueva línea (cambiar a la siguiente línea)
Cuando usamos el lenguaje C \n
para el salto de línea, a nivel de lenguaje, se realizan por defecto dos acciones de salto de línea + retorno de carro .
2. El concepto de búfer de línea
pregunta:
Primero observemos la diferencia entre las siguientes dos piezas de código después de ejecutar bajo Linux
-
El archivo ejecutable de las dos piezas de código se llamará MyTest y se ejecutará para mostrar
-
Las funciones se usarán en el código
sleep
, puede usar el comando man para encontrarlo en el manual No. 3 ( comandos comunes de Linux )man 3 sleep
- Función: Pausa en el código actual, en segundos.
código 1
#include<stdio.h>
#include<unistd.h>
int main()
{
printf("hello world\n");//使用换行符'\n'
sleep(3);//暂停3秒后继续运行
return 0;
}
codigo 2
#include<stdio.h>
#include<unistd.h>
int main()
{
printf("hello world\r");//使用回车符'\r'
sleep(3);//暂停3秒后继续运行
return 0;
}
De acuerdo con nuestra lógica normal, ambas piezas de código deberían imprimir algo, pero el código 2 solo ejecuta dormir y no se imprime nada, ¿por qué? ¿Tiene algo
\r
que\n
ver?
Este problema involucra el concepto del área de caché (vamos a entender brevemente aquí, el contenido restante del búfer estará en un blog posterior)
respuesta:
Echemos un vistazo al siguiente código y sus resultados de ejecución:
codigo 3
#include<stdio.h>
#include<unistd.h>
int main()
{
printf("hello world");
sleep(3);//暂停3秒后继续运行
return 0;
}
Podemos ver los resultados anteriores, parece que esta vez la función de suspensión se ejecuta primero, después de ejecutar printf y después de la cadena de salida, se emite la línea de comando.
-
El código en lenguaje C ejecuta una estructura secuencial , la cual debe ejecutarse en secuencia y lógica de código, por lo que primero se debe ejecutar printf, y luego dormir.
-
Printf se ejecuta, y debe haber un lugar para almacenar cadenas temporalmente, y este lugar es el área de búfer .
-
Cuando se ejecuta el código, el área del búfer se actualiza y la cadena se imprime en la pantalla. En este momento , la posición del cursor (cursor verde) está detrás de la cadena.
-
En Linux, cada vez que los datos se imprimen en el monitor, comienzan desde la posición del cursor, es decir, el cursor coincide con el monitor, donde está el cursor, la impresión comienza allí.
-
Entonces, la línea de comando se imprimirá directamente después de la cadena. ( El código 1 tiene un salto de línea y el cursor está en una nueva línea)
-
Los diferentes búferes de plataforma tienen diferentes expresiones. En Linux, el búfer tiene su propia estrategia de actualización (muchas)
Lo que estamos viendo ahora es el caché de línea , que actualizará el área del caché en seis situaciones (solo se presentan tres, y el resto es irrelevante para este artículo)
- Se encuentra un carácter de nueva línea, como:
\n
. ( El código 1 primero ve la cadena y luego duerme) - cuando termina el programa. ( en el caso del código tres )
- actualización activa
- Se encuentra un carácter de nueva línea, como:
Del contenido anterior, podemos analizar las razones de la ejecución fallida del código 2 :
Después de ejecutar la función printf, el búfer no se actualiza y los datos se guardan en el búfer.Después de que se ejecuta la suspensión, la cadena se imprime en la pantalla, pero en el contenido anterior lo especificamos
\r
como un retorno de carro, y el cursor regresó al final de la línea izquierda, luego la línea de comando se imprime al comienzo del cursor, sobrescribiendo el contenido de la cadena. Ya no podemos ver nada.
Entonces, ¿hay alguna manera de arreglar esto? Respuesta: No puedo pensar en eso, siempre que lo \r
coloquemos al final de la cadena, la línea de comando eventualmente sobrescribirá la cadena. Incluso si usamos otros caracteres de control para mostrar el resultado, el resultado es diferente de lo que queremos después de todo.
Aquí podemos usar el tercer método de actualizar el caché descrito anteriormente para verificar si nuestra respuesta es correcta y ver la cadena aparecer y desaparecer en la pantalla.
Detección:
Si queremos actualizar activamente el búfer, necesitamos usar fflush
funciones.También podemos usar el comando man para encontrarlo en el manual No. 3. Comandos comunes de Linux
man 3 fflush
El código de prueba es el siguiente:
#include<stdio.h>
#include<unistd.h>
int main()
{
printf("hello world\r");//使用回车符'\r'
fflush(stdout);//自动刷新缓存区
sleep(3);//暂停3秒后继续运行
return 0;
}
Podemos ver en los resultados que este es el caso, su cursor se mueve hacia el extremo izquierdo y se sobrescribe cuando se imprime la línea de comando, y no podemos ver el resultado en el Código 2 .
expandir
Todo lo impreso en la pantalla es un carácter.
printf("%d",123);
//打印的123,分别为'1'、'2'、'3'
3. Barra de progreso
Visualización de resultados:
Podemos usar el conocimiento del búfer anterior para implementar un programa tan pequeño en Linux usando lenguaje C
Simplemente podemos dividir un programa tan pequeño en cuatro partes como se muestra en la siguiente figura:
1. Barra dinámica de progreso
El gráfico del crecimiento de la barra de progreso lo puse en =
, y empiezo con el >
símbolo
La configuración de la barra de progreso es de 0% a 100% (0% no tiene progreso), necesitamos 100 piezas de tamaño =
, y una más >
, y agregamos un terminador al final \0
, se almacenan un total de 102 bytes, que es el carácter para almacenar la barra de progreso El tamaño de la matriz de tipo es 102.
Nota: Después de crear la matriz, debe continuar inicializándola para que tenga 102 bytes, de modo que pueda \0
detenerse con precisión cada vez que alcance la posición actualizada.
Queremos que se actualice cada 1% de la carga. Necesitamos poner la matriz impresa en el bucle y \r
colocarla detrás de la cadena que se va a imprimir. Úselo fflush(stdout)
para actualizar automáticamente el área del búfer. Use usleep
(unidad de sueño segundos, unidad de sueño us Sutil, puedes probarlo tú mismo para ver cuál es más adecuado) Pausa cada ciclo y continúa, para que puedas mostrar la forma de la barra de progreso subiendo.
2. Porcentaje de progreso
Imprimimos la barra de progreso en el bucle, siempre que se imprima el número de bucles al imprimir. Nota: el signo de porcentaje significa que %%
no se puede usar \%
, y se emitirá una alarma. Si la compilación en la primera plataforma falla, se será mostrado.
Modifique el código anterior de la siguiente manera
printf("[%-100s][%d%%]\r",bar,i);
3. Pequeñas decoraciones
Al final de la barra de progreso, agregamos un cursor giratorio para que se vea más vívido,
Aquí | / - \
se usan cuatro símbolos para representar el cursor y se almacenan en una matriz. Nota: \ representa un carácter de cambio, y dos \ se usan para representar uno
Girar en el sentido de las agujas del reloj: "|/-\"
Girar en sentido contrario a las agujas del reloj: "|\-/"
Aquí se utiliza el sentido de las agujas del reloj, y el código modificado completo es el siguiente:
#include<stdio.h>
#include<unistd.h>
#include<string.h>
#define N 101
#define STYLE '='
int main()
{
char bar[N];
memset(bar,'\0',sizeof(bar));
char lable[4] = "|/-\\";
int i=0;
while(i<=100)
{
printf("[%-100s][%d%%][%c]\r",bar,i,lable[i%4]);
fflush(stdout);
usleep(100000);
bar[i++] = STYLE;
if(i!=100) bar[i] = '>';
}
printf("\n");
return 0;
}
4. color
Hay muchas formas de cambiar el color de la barra de progreso que mostramos, aquí solo muestro una, los interesados pueden buscarla por sí mismos.
//格式
printf("\e[31m字符串\e[0m");
//31:前景色
//\e[31 :开头
//\e[0m :终止,使改变的颜色只在字符串内
color de primer plano (color de fuente)
personaje | color |
---|---|
30 | negro |
31 | rojo |
32 | verde |
33 | amarillo |
34 | azul |
35 | Púrpura |
36 | verde oscuro |
37 | Blanco |
Con este conocimiento, podemos cambiar el color de la barra de progreso, volviéndola roja, el código es el siguiente:
#include<stdio.h>
#include<unistd.h>
#include<string.h>
#define N 101
#define STYLE '='
int main()
{
char bar[N];
memset(bar,'\0',sizeof(bar));
const char* lable = "|/-\\";
int i=0;
while(i<=100)
{
printf("[\e[31m%-100s\e[0m][%d%%][%c]\r",bar,i,lable[i%4]);
fflush(stdout);
usleep(100000);
bar[i++] = STYLE;
if(i!=100) bar[i] = '>';
}
printf("\n");
return 0;
}
El color y la forma de la barra de progreso no son los únicos. Si está interesado, puede buscar más contenido y crear una barra de progreso especial usted mismo.