2009-02-13 17 views
12

Quiero leer sizeof(int) bytes de una matriz char*.Lectura de bytes de tamaño "entero" de una matriz char *.

a) ¿En qué situaciones tenemos que preocuparnos si se debe verificar la permanencia?

b) ¿Cómo leería los primeros 4 bytes teniendo en cuenta la endianidad o no?

EDITAR: El sizeof(int) bytes que he leído debe compararse con un valor entero.

¿Cuál es la mejor manera de ir sobre este problema

+0

Estoy un poco confundido acerca de lo que estás tratando de hacer. ¿Podría escribir algún pseudocódigo, como ejemplo? ¿Estás tratando de analizar enteros de la matriz de caracteres? –

+0

Estoy tratando de encontrar el tamaño de los bytes (int) de una matriz char * e intentando compararlo con un número entero. La fuente de los datos es una máquina diferente. – kal

Respuesta

1

Usted no debería tener que preocuparse por endianess a menos que esté leyendo los bytes de una fuente crea en un equipo diferente, por ejemplo, una corriente de red.

Teniendo en cuenta que, ¿no se puede simplemente utilizar un bucle for?

void ReadBytes(char * stream) { 
    for (int i = 0; i < sizeof(int); i++) { 
     char foo = stream[i]; 
     } 
    } 
} 

¿Estás pidiendo algo más complicado que eso?

+0

Mis datos realmente se crean a partir de una fuente diferente – kal

1

Debe preocuparse por la endiadencia solo si los datos que está leyendo se componen de números que son más grandes que un byte.
si está leyendo sizeof (int) bytes y espera interpretarlos como un int, endianess hace la diferencia. esencialmente endianness es la forma en que una máquina interpreta una serie de más de 1 bytes en un valor numérico.

3

depende de cómo se desea leerlos, me da la sensación de que deseas fundido 4 bytes en un entero, hacerlo sobre la red transmite datos por lo general terminan en algo como esto:

int foo = *(int*)(stream+offset_in_stream); 
+1

Eso puede dar como resultado un acceso no alineado. – gimpf

+0

@gimpf: Tengo curiosidad: ¿con qué sistemas se generará un error? – Christoph

+0

, es decir en 80486 y cualquier CPU mejor con el conjunto Align-Flag. –

18

Do que quiere decir algo así ?:

char* a; 
int i; 
memcpy(&i, a, sizeof(i)); 

usted sólo tiene que preocuparse por endianess si la fuente de los datos es desde una plataforma diferente, como un dispositivo.

+0

¿Qué podría ser más obvio? : D –

+0

Esta es una buena forma legal sin romper las reglas de tipo de juego de palabras/alias. Para aquellos que se preguntan, "¡pero se ve más lento que un yeso!" a) el reparto es un comportamiento indefinido, así que no vayas allí b) el código generado no es diferente para x86/x64: https://godbolt.org/g/gxtVFZ – Eloff

1

Simplemente use un bucle for que se mueve sobre la matriz en tamaño de fragmentos (int).
Utilice la función ntohl (que se encuentra en el encabezado <arpa/inet.h>, al menos en Linux) para convertir bytes en el orden de la red (el orden de la red se define como big-endian) al orden de bytes local. Esa función de biblioteca se implementa para realizar la conversión correcta de red a servidor para cualquier procesador en el que se esté ejecutando.

+0

Por supuesto, esto aplica solo si estás de hecho, está leyendo algo de la red ... – gimpf

+0

Bien, dijo en el comentario que lo está leyendo desde una máquina diferente. Bueno, tal vez hecho al grabar/leer un CD, pero más probablemente de hecho significó algún tipo de red. – gimpf

9

a) Solo debe preocuparse por la "endianidad" (es decir, byte-swapping) si los datos se crearon en una máquina big-endian y se están procesando en una máquina little-endian, o viceversa. Hay muchas maneras en que esto puede ocurrir, pero aquí hay un par de ejemplos.

  1. Recibes datos en una máquina con Windows a través de un socket. Windows emplea una arquitectura little-endian mientras que se supone que los datos de la red están en formato big-endian.
  2. Procesa un archivo de datos que se creó en un sistema con una "endianidad" diferente.

En cualquiera de estos casos, tendrá que cambiar byte todos los números que son más grandes que 1 byte, p., cortos, ints, longs, doubles, etc. Sin embargo, si siempre está tratando con datos de la misma plataforma, los problemas de endian no son importantes.

b) Según su pregunta, parece que tiene un puntero de char y desea extraer los primeros 4 bytes como int y luego tratar con cualquier problema endian. Para hacer la extracción, utilice esto:

int n = *(reinterpret_cast<int *>(myArray)); // where myArray is your data 

Obviamente, esto supone miMatriz no es un puntero nulo; de lo contrario, se bloqueará ya que desreferencia el puntero, por lo tanto, emplee un buen esquema de programación defensivo.

Para intercambiar los bytes en Windows, puede usar las funciones ntohs()/ntohl() y/o htons()/htonl() definidas en winsock2.h. O puede escribir algunas rutinas sencillas de hacer esto en C++, por ejemplo:

inline unsigned short swap_16bit(unsigned short us) 
{ 
    return (unsigned short)(((us & 0xFF00) >> 8) | 
          ((us & 0x00FF) << 8)); 
} 

inline unsigned long swap_32bit(unsigned long ul) 
{ 
    return (unsigned long)(((ul & 0xFF000000) >> 24) | 
          ((ul & 0x00FF0000) >> 8) | 
          ((ul & 0x0000FF00) << 8) | 
          ((ul & 0x000000FF) << 24)); 
} 
+1

debe mencionar que el primer fragmento de código tiene el mismo problema que Daniels ': puede acceder a datos no alineados que no son adecuados para int * –

3

La forma más fácil de resolver esto es para asegurarse de que lo genera los bytes lo hace de una orden de bits constante. Normalmente, el "orden de bytes de red" utilizado por varias cosas TCP/IP es mejor: las rutinas de biblioteca htonl y ntohl trabajo muy bien con esto, y son por lo general bastante bien optimizado.

Sin embargo, si no se está utilizando la orden de bytes de la red, es posible que deba hacer otras cosas en . Necesita saber dos cosas: el tamaño de un entero y el orden de bytes. Una vez que sepa eso, sabrá cuántos bytes extraer y en qué orden ponerlos juntos en un int.

un código de ejemplo que asume sizeof (int) es el número correcto de bytes:

#include <limits.h> 

int bytes_to_int_big_endian(const char *bytes) 
{ 
    int i; 
    int result; 

    result = 0; 
    for (i = 0; i < sizeof(int); ++i) 
     result = (result << CHAR_BIT) + bytes[i]; 
    return result; 
} 

int bytes_to_int_little_endian(const char *bytes) 
{ 
    int i; 
    int result; 

    result = 0; 
    for (i = 0; i < sizeof(int); ++i) 
     result += bytes[i] << (i * CHAR_BIT); 
    return result; 
} 


#ifdef TEST 

#include <stdio.h> 

int main(void) 
{ 
    const int correct = 0x01020304; 
    const char little[] = "\x04\x03\x02\x01"; 
    const char big[] = "\x01\x02\x03\x04"; 

    printf("correct: %0x\n", correct); 
    printf("from big-endian: %0x\n", bytes_to_int_big_endian(big)); 
    printf("from-little-endian: %0x\n", bytes_to_int_little_endian(little)); 
    return 0; 
} 

#endif 
+0

Ahora reemplace "int" por "unsigned" y su respuesta es correcta;) –

+1

reemplazaría el + y + = con | y | = respectivamente. es confuso usar operadores matemáticos aquí. –

1

¿Por qué leer cuando se puede comparar?

bool AreEqual(int i, char *data) 
{ 
    return memcmp(&i, data, sizeof(int)) == 0; 
} 

Si está preocupado por el endianness cuando necesita convertir todos los enteros a alguna forma invariable. htonl y ntohl son buenos ejemplos.

+0

Esto siempre devolverá falso. Creo que te refieres a memcmp(), no a memcpy(). –

+0

Gracias, corregido. – okutane

3

¿Qué tal

int int_from_bytes(const char * bytes, _Bool reverse) 
{ 
    if(!reverse) 
     return *(int *)(void *)bytes; 

    char tmp[sizeof(int)]; 

    for(size_t i = sizeof(tmp); i--; ++bytes) 
     tmp[i] = *bytes; 

    return *(int *)(void *)tmp; 
} 

Se podría utilizar de esta manera:

int i = int_from_bytes(bytes, SYSTEM_ENDIANNESS != ARRAY_ENDIANNESS); 

Si estás en un sistema en el que la fundición void *-int * den lugar a conflictos de alineación, se puede usar

int int_from_bytes(const char * bytes, _Bool reverse) 
{ 
    int tmp; 

    if(reverse) 
    { 
     for(size_t i = sizeof(tmp); i--; ++bytes) 
      ((char *)&tmp)[i] = *bytes; 
    } 
    else memcpy(&tmp, bytes, sizeof(tmp)); 

    return tmp; 
} 
Cuestiones relacionadas