2010-08-18 12 views
7

tengo una matriz que es así:memcpy añade ff ff ff al comienzo de un byte

unsigned char array[] = {'\xc0', '\x3f', '\x0e', '\x54', '\xe5', '\x20'}; 
unsigned char array2[6]; 

Cuando uso memcpy:

memcpy(array2, array, 6); 

e imprimir ambos:

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 impresiones

ffffffc0 3f e 54 ffffffe5 20 

lo que pasó?

+4

¿Puedes verificar la definición de 'array2'? –

+3

Parece tratar array2 como ints con signo en lugar de caracteres sin signo. –

+0

array2 es un char sin signo [] – Hock

Respuesta

13

me he vuelto su código en un ejemplo compilables completa. 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 los que esperaba.

c0 3f e 54 e5 20 
c0 3f e 54 e5 20 
ffffffc0 3f e 54 ffffffe5 20 

Como se puede ver, sólo cuando la matriz es de un tipo char firmado hacer el 'extra' ff conseguir adjuntas. El motivo es que cuando memcpy rellena la matriz del char con signo, los valores con un alto bit establecido ahora corresponden a los valores negativos char. Cuando se pasa al printf, el char se promociona a los tipos int, lo que significa una extensión de signo.

%x los imprime en hexadecimal como si fueran unsigned int, pero a medida que el argumento se pasa como int el comportamiento es técnicamente definido. Por lo general, en una máquina complementaria de dos, el comportamiento es el mismo que el estándar firmado para conversión sin signo que usa la aritmética mod 2^N (donde N es el número de bits de valor en unsigned int). Como el valor fue solo "ligeramente" negativo (procedente de un tipo firmado estrecho), la conversión posterior está cerca del valor unsigned int máximo posible, es decir, tiene muchos 1 (en binario) o f en hexadecimal.

+0

Siempre debe tener cuidado al verificar el valor de la memoria con una declaración de estilo de impresión; es mucho mejor usar el depurador –

2

% x formato espera tipo entero. Trate de usar de calidad:

 
printf("%x %x %x %x %x %x", (int)array2[0], ... 

Editar: Puesto que hay nuevos comentarios de mi post, quiero añadir un poco de información. Antes de llamar a la función printf, el compilador genera un código que empuja la lista de parámetros de la pila apilada (...). El compilador no sabe nada sobre los códigos de formato de impresión, y empuja los parámetros de acuerdo con su tipo. printf recopila parámetros de la pila de acuerdo con la cadena de formato. Por lo tanto, array [i] se empuja como char, y manejado por printf como int. Por lo tanto, siempre es una buena idea hacer casting, si el tipo de parámetro no coincide exactamente con la especificación de formato, trabajando con funciones printf/scanf.

+0

char es del tipo entero. C99 std: 6.2.5 para 4: 'Hay cinco tipos de entero con signo estándar, designados como char firmado, corto int, int, long int y long long int. (Estos y otros tipos pueden ser designados de varias maneras adicionales, como se describe en 6.7.2.) ' – osgx

+0

Pero un char no se puede pasar en la pila en cuatro bytes, que es lo que'% x' esperará. –

+0

la llamada de función promocionará la char a int (y completará el bit de la promoción existente) – KevinDTimm

4

El problema no es memcpy (a menos que su tipo de carácter son realmente 32 bits, en lugar de 8), parece más una extensión de signo entero durante la impresión.

es posible que desee cambiar su printf para utilizar explícitamente la conversión de caracteres sin signo, es decir.

printf("%hhx %hhx...", array2[0], array2[1],...); 

Como una suposición, es posible que su compilador/optimizador está manejando array (cuyo tamaño y contenido que se conoce en tiempo de compilación) y array2 diferente, empujando a valores constantes en la pila en el primer lugar y empujando erróneamente signo valores extendidos en el segundo.

4

Usted debe enmascarar los bits más altos, ya que sus caracteres se extenderán a int tamaño cuando se llama a una función varargs:

printf("%x %x %x %x %x %x", array[0] & 0xff, // .. 
+0

% hhx es mejor. – osgx

+0

@osgx - sí, pero nosotros viejos c chicos aprendieron hace mucho tiempo a & 0xff :) viejos hábitos mueren duro – KevinDTimm

+2

'% hhx' no es (todavía) C++, recuerde que C++ se refiere a la versión estándar pre-C99 para su 'printf' contrato. –

Cuestiones relacionadas