Acerca de los errores causados por las constantes de enumeración

prefacio

Registra un error causado por un error de mano que Ken compartió en el grupo el 30 de mayo de 2020.

Descripción del problema

Las palabras originales del hermano Ken:
es hora de la discusión del tema abierto todos los días nuevamente, aprendamos algo mientras pescamos juntos. Hoy vamos a hablar sobre un tema: errores accidentales, a veces el código puede ejecutarse y a veces habrá problemas. ¿qué pasó? ¿Te has encontrado con problemas extraños similares? Todos son bienvenidos a hablar sobre escenarios de problemas similares que hayan encontrado en el estudio y el trabajo reales.
Es hora de la discusión diaria de temas abiertos nuevamente, aprendamos algo de la pesca juntos. Hoy vamos a hablar sobre un tema: error manual accidental, a veces el código puede ejecutarse y a veces habrá problemas. ¿Qué está pasando entonces? ¿Te has encontrado con problemas extraños similares? Todos son bienvenidos a hablar sobre escenarios de problemas similares que hayan encontrado en el estudio y el trabajo reales.

/* 一个信息的记录表 */
static const char *g_msg_tab[] = 
{
    
    
	"SUCESS",
	"NO SUCH FILE",
	"IO ERROR",
	"BAD FILE NUM",
	"OUT OF MEM"
	"FILE EXIST",
	"NO SUCH DEVICE",
	"UNKNOWN ERROR",
};
void send_err_msg_out(int err_index)
{
    
    
	char msg[16] = {
    
    0};
	
	snprintf(msg, sizeof(msg), "%s", g_msg_tab[err_index]);
	
	//send out ...
}

análisis del problema

(1) Para ser honesto, miré este código durante mucho tiempo y no encontré el problema. Más tarde, el jefe del grupo me recordó que faltaba una coma, así que la encontré.

inserte la descripción de la imagen aquí

(2) En la definición de la constante de enumeración, ¿no debería informarse un error si falta un ','? Este es un punto que los grandes del grupo se preguntan, pero lo descubrieron después de la práctica. De hecho, puede funcionar.
Debido a que el código de Ken no tiene una función principal, no se puede ejecutar directamente. Así que agregué la función principal aquí.
Hay un problema al que se debe prestar atención aquí. Parece que la versión anterior del compilador informará un error al compilar la función snprintf. Soy demasiado perezoso para lidiar con eso, así que simplemente lo puse en Linux y ejecuté él.

#include <stdio.h>
/* 一个信息的记录表 */
static const char *g_msg_tab[] =
{
    
    
        "SUCESS",
        "NO SUCH FILE",
        "IO ERROR",
        "BAD FILE NUM",
        "OUT OF MEM"
        "FILE EXIST",
        "NO SUCH DEVICE",
        "UNKNOWN ERROR",
};
void send_err_msg_out(int err_index)
{
    
    
        char msg[16] = {
    
     0 };

        snprintf(msg, sizeof(msg), "%s", g_msg_tab[err_index]);

        //send out ...
}
int main()
{
    
    
        printf("hello world\r\n");
        send_err_msg_out(0);
        return 0;
}

inserte la descripción de la imagen aquí

el resultado del problema

(1) Falta un ',' en la constante de enumeración. Descubrimos que no se informó ningún error, así que decidí imprimir el cuarto parámetro de la constante de enumeración para ver cuál era el resultado.
(2) ¡Más tarde, se descubrió que la cuarta cuerda se convirtió en una superposición de dos cuerdas!
(3) Cuando el hermano Ken anunció la respuesta más tarde, dijo, "el compilador es mucho más inteligente de lo que imaginamos. El problema aquí es que a la cadena en la línea 5 le falta una coma. Aunque no hay problema con la compilación, el compilador pondrá La cadena de caracteres de 5 líneas y la cadena de caracteres de la 6ª línea se fusionan en una cadena de caracteres, que se almacena en la posición de g_msg_tab[4].

inserte la descripción de la imagen aquí

¿Cómo puede la escritura ser capaz de exponer este problema?

solución de errores

(1) El hermano Ken dijo más tarde, porque es muy inteligente definir una matriz de cadenas aquí, usando el método de *xxx[ ] para adaptar el número de elementos, es decir, no hay un número fijo en [ ], y el compilador lo compilará por sí mismo Decide el espacio.
(2) Si se usa una matriz bidimensional estándar para definir, este problema de error puede haberse expuesto hace mucho tiempo, es decir, la forma es como xxx[8][16].
(3) Algunas personas pueden tener dudas en este momento, ¿por qué se puede exponer el problema cuando se escribe como una matriz bidimensional?
(4) Antes que nada, necesitamos saber un concepto básico, ¿qué es una cadena en lenguaje C?Una cadena en lenguaje C es esencialmente un puntero, que apunta a un segmento .rodata, que es un segmento especial que se usa para almacenar datos de solo lectura, como constantes de cadena y constantes globales..
(5) g_msg_tab[] es una matriz de punteros para almacenar estas cadenas. Y si usamos una matriz bidimensional para almacenar, ¿no puede entenderse la matriz bidimensional como una matriz de punteros? (¡Nota, hay una diferencia!) Sin embargo, el tamaño del área señalada por este puntero está regulado Tomando xxx[8][16] como ejemplo, el tamaño del área señalada por esta matriz de punteros es como máximo 16 bytes El área a la que apunta el puntero en g_msg_tab[] no tiene requisitos de tamaño, siempre que no supere el tamaño de almacenamiento del segmento .rodata.
(6) Después de conocer la diferencia entre matrices de punteros y matrices bidimensionales, no debería ser difícil para nosotros sacar conclusiones. ¿Cómo se expone este problema? Limitando el tamaño del área apuntada por el puntero.

inserte la descripción de la imagen aquí

¿Este método realmente funciona?

(1) Algunas personas pueden haberlo pensado, ¿puede este método realmente eliminar tales problemas? Dado que la matriz bidimensional puede especificar la cantidad de caracteres especificados almacenados en la ubicación, ¿no debería ser suficiente si los datos almacenados son exactamente iguales a la cantidad de caracteres especificada?
(2) Así que hice los siguientes cambios. Originalmente, los datos después de la combinación de "FUERA DE MEM" y "EXISTE EL ARCHIVO" tienen más de 16 caracteres. Ahora lo dejo intentar igualar exactamente 16 caracteres.
(3) Resultó que la compilación pasó. Pero imprime una línea más. ¿Cuál es el problema con esto?

inserte la descripción de la imagen aquí

(4) Después de pensarlo, de repente se me ocurrió. Mi printf está usando %s. El principio de funcionamiento de %s es detectar "\0" antes de detenerse. Debido a que aquí tiene exactamente 16 caracteres, "\0" está cubierto, solo lo tiene la línea adicional. Por lo tanto, el área a la que realmente apunta esta matriz bidimensional solo puede almacenar 15 caracteres.

inserte la descripción de la imagen aquí

Resumir

(1) De hecho, este es un pequeño punto de conocimiento del lenguaje C, pero es fácil ignorarlo. En cuanto a cómo evitar este problema, no he pensado en un método adecuado, por lo que solo puedo sugerir que tengas cuidado.
(2) Este error es repugnante porque el compilador no puede solicitar, por lo que si hay problemas inexplicables. Solo puedo recordarle que verifique si olvidó escribir un ',' en la constante de enumeración.

Supongo que te gusta

Origin blog.csdn.net/qq_63922192/article/details/131134034
Recomendado
Clasificación