Memcpy agrega ff ff ff al comienzo de un byte
Pregunta
Tengo una matriz que es así:
unsigned char array[] = {'\xc0', '\x3f', '\x0e', '\x54', '\xe5', '\x20'};
unsigned char array2[6];
Cuando uso memcpy:
memcpy(array2, array, 6);
E imprima los dos:
printf("%x %x %x %x %x %x", array[0], // ... etc
printf("%x %x %x %x %x %x", array2[0], // ... etc
Uno imprime como:
c0 3f e 54 e5 20
Pero el otro imprime
ffffffc0 3f e 54 ffffffe5 20
¿qué sucedió?
Solución
He convertido su código en un ejemplo compilable completo. También agregué una tercera matriz de un 'normal' char
que en mi entorno está firmado.
#include <cstring>
#include <cstdio>
using std::memcpy;
using std::printf;
int main()
{
unsigned char array[] = {'\xc0', '\x3f', '\x0e', '\x54', '\xe5', '\x20'};
unsigned char array2[6];
char array3[6];
memcpy(array2, array, 6);
memcpy(array3, array, 6);
printf("%x %x %x %x %x %x\n", array[0], array[1], array[2], array[3], array[4], array[5]);
printf("%x %x %x %x %x %x\n", array2[0], array2[1], array2[2], array2[3], array2[4], array2[5]);
printf("%x %x %x %x %x %x\n", array3[0], array3[1], array3[2], array3[3], array3[4], array3[5]);
return 0;
}
Mis resultados fueron lo que esperaba.
c0 3f e 54 e5 20
c0 3f e 54 e5 20
ffffffc0 3f e 54 ffffffe5 20
Como puede ver, solo cuando la matriz es de un tipo de char firmado, haga el 'extra' ff
Agradecer. La razón es que cuando memcpy
pobla la matriz de firmado char
, los valores con un conjunto de bits alto ahora corresponden a negativos char
valores. Cuando se pasó a printf
la char
son promovidos a int
tipos que significan efectivamente una extensión de signo.
%x
los imprime en hexadecimal como si fueran unsigned int
, pero a medida que el argumento se pasó como int
El comportamiento está técnicamente indefinido. Por lo general, en una máquina de complemento de un dos, el comportamiento es el mismo que el estándar firmado en conversión sin firmar que utiliza la aritmética mod 2^n (donde n es el número de bits de valor en un unsigned int
). Como el valor fue solo 'ligeramente' negativo (proveniente de un tipo estrecho firmado), la conversión posterior al valor está cerca del máximo posible unsigned int
valor, es decir, tiene muchos liderazgo 1
's (en binario) o liderazgo f
en hex.
Otros consejos
El problema no es memcpy
(A menos que su tipo de char realmente sea 32 bits, en lugar de 8), se parece más a la extensión de signo entero mientras se imprime.
Es posible que desee cambiar su printf para usar explícitamente la conversión de char sin firmar, es decir.
printf("%hhx %hhx...", array2[0], array2[1],...);
Como suposición, es posible que su compilador/optimizador esté manejando array
(cuyo tamaño y contenido se conocen en el momento de la compilación) y array2
de manera diferente, empujar valores constantes en la pila en primer lugar y empujar erróneamente los valores extendidos en el segundo.
Debe enmascarar los bits más altos, ya que sus caracteres se extenderán a int
tamaño al llamar a una función varargs:
printf("%x %x %x %x %x %x", array[0] & 0xff, // ..
El formato %X espera el tipo de entero. Intenta usar el casting:
printf("%x %x %x %x %x %x", (int)array2[0], ...
EDITAR: Dado que hay nuevos comentarios en mi publicación, quiero agregar información. Antes de llamar a la función Printf, el compilador genera código que presiona la lista de parámetros de la variable pila de parámetros (...). El compilador no sabe nada sobre los códigos de formato printf y empuja los parámetros de acuerdo con su tipo. Printf recopila parámetros de la pila de acuerdo con la cadena de formato. Entonces, la matriz [i] se empuja como char, y se maneja por printf como int. Por lo tanto, siempre es una buena idea hacer que la fundición, si el tipo de parámetro no coincide exactamente con la especificación de formato, trabajando con funciones printf/scanf.