Un pozo en sscanf

En un proyecto, usé accidentalmente sscanf. No explicaré su uso en detalle aquí. Comencemos con el punto y hablemos sobre la intención de este artículo. También espero que otros hermanos de la misma familia lo entiendan.

El código del programa:

struct xxx{
        unsigned char a[6];
        char    b[16];
};
int main(int argc, char** argv)
{
        struct xxx  xyz;
        memset(&xyz, 0, sizeof(struct xxx));
        strcpy(xyz.b, argv[1]);
        sscanf(argv[2], "%x:%x:%x:%x:%x:%x", &(xyz.a[0]), &(xyz.a[1]), &(xyz.a[2]), &(xyz.a[3]), &(xyz.a[4]), &(xyz.a[5]));
        printf("%s\n", xyz.b);
        return 0;
}

Ejecución: ./test enp2s0 12: 23: 34: 45: 45: 56

Resultado de la impresión: la salida xyz.b está vacía

gcc -g test.c -o test

Resultados de depuración en GDB:

 

Explique, el primer paso es inicializar la memoria de la variable xyz a 0;

El segundo paso es asignar un valor a xyz.b a través de strcpy, que se muestra en hexadecimal en la figura;

En la tercera parte, después de ejecutar sscanf, el valor numérico de xyz.a se asigna al elemento, pero los primeros tres bytes de xyz.b se establecen en 0.

Finalmente, la salida de xyz.b está vacía.

Explicación de la razón: Debemos abandonar la metafísica heredada de nuestros antepasados, los problemas encontrados en el proceso de desarrollo deben tener razones. El problema aquí, obviamente, apareció después de ejecutar sscanf, por lo que solo puede analizar el uso de sscanf en profundidad.

Especificador de tipo sscanf:

Tipos de

Entrada calificada

Tipo de parámetro

C

Carácter único: lee el siguiente carácter. Si se especifica un ancho distinto de 1, la función leerá caracteres de ancho, los pasará a través de parámetros y los almacenará en posiciones consecutivas en la matriz. No se agregará ningún carácter nulo al final.

char *

re

Entero decimal: el signo + o delante del número es opcional.

En t *

e, E, f, g, G

Número de coma flotante: contiene un punto decimal, un prefijo opcional + o -, un carácter posterior opcional e o E y un número decimal. Dos ejemplos válidos: 732.103 y 7.12e4

flotar *

O

Entero octal.

En t *

s

Cuerda. Esto leerá caracteres consecutivos hasta que se encuentre un carácter de espacio (el carácter de espacio puede ser espacio en blanco, salto de línea y tabulación).

char *

tu

Entero decimal sin signo.

unsigned int *

x, X

Entero hexadecimal.

En t *

sscanf (argv [2], "% x:% x:% x:% x:% x:% x", & (xyz.a [0]), & (xyz.a [1]), & (xyz .a [2]), & (xyz.a [3]), & (xyz.a [4]), & (xyz.a [5]));

% X se usa en el programa, y ​​el tipo de parámetro de entrada correspondiente debe ser int *, lo que indica que el tipo original del parámetro debe ser de 4 bytes, y cada elemento de la matriz xyz.a es un byte. Cuando es una memoria copy, xyz.a [5] La representación hexadecimal copiada real es 0x00000067. El almacenamiento de memoria de la plataforma x86_64 está en orden de bytes little-endian (byte alto en byte alto, byte bajo en byte bajo), y aquí GDB muestra de byte bajo a byte alto, de izquierda a derecha, así que aquí está el encabezado de xyz Tres bytes están cubiertos por tres 0x00.

Por lo tanto, solo la dirección mac de cadena en el programa se puede convertir a int, y el prototipo del parámetro de entrada scanf no admite caracteres sin signo. De hecho, desde este programa solo, el orden de asignación de xyz.a y xyz.b se puede intercambiar, y también se puede realizar. Echemos un vistazo:

Pero recuerde, use este método para convertir direcciones mac con precaución en proyectos reales, de lo contrario, definitivamente pagará el precio. !

 

 

 

Supongo que te gusta

Origin blog.csdn.net/qq_24436765/article/details/107361854
Recomendado
Clasificación