2009-10-05 16 views
17

Quiero almacenar un int de 4 bytes en una matriz char ... de modo que las primeras 4 ubicaciones de la matriz char son los 4 bytes del int.¿Almacena una int en una matriz char?

Entonces, quiero tirar de la int de nuevo fuera de la matriz ...

Además, los puntos de bonificación si alguien me puede dar el código para hacer esto en un bucle ... es decir, escribir como 8 enteros en una Matriz de 32 bytes.

int har = 0x01010101; 
char a[4]; 
int har2; 

// write har into char such that: 
// a[0] == 0x01, a[1] == 0x01, a[2] == 0x01, a[3] == 0x01 etc..... 

// then, pull the bytes out of the array such that: 
// har2 == har 

Gracias chicos!

EDIT: Supongamos int son 4 bytes ...

Edit2: Por favor, no se preocupan por orden de bits ... que se preocuparse por orden de bits. Solo quiero diferentes formas de lograr lo anterior en C/C++. Gracias

EDIT3: Si no puede ver, estoy tratando de escribir una clase de serialización en el nivel bajo ... así que estoy buscando diferentes estrategias para serializar algunos tipos de datos comunes.

+8

tal vez debería hacer su propia tarea ... Y luego, si tiene alguna duda, puede publicar su código aquí y trataremos de ayudarle a continuación. Si no tratas de hacerlo tú mismo, no vas a aprender nada. – jpmelos

+1

LOL esto no es tarea :) – Polaris878

+1

Si estuviera escribiendo C, sabría mejor que para inicializar una variable con un valor. – jkeys

Respuesta

20

No es la manera más óptima, pero es endian seguro.


int har = 0x01010101; 
char a[4]; 
a[0] = har & 0xff; 
a[1] = (har>>8) & 0xff; 
a[2] = (har>>16) & 0xff; 
a[3] = (har>>24) & 0xff; 
+0

¿Esto tiene problemas si har es negativo? (Parece recordar que hay algo extraño sobre el cambio de bits y las notas negativas ...) –

37

A menos que usted se preocupa por el orden de bytes y tal, memcpy hará el truco:

memcpy(a, &har, sizeof(har)); 
... 
memcpy(&har2, a, sizeof(har2)); 

Por supuesto, no hay garantía de que sizeof(int)==4 en cualquier implementación particular (y hay implementaciones del mundo real para el cual este es de hecho falso).

Escribir un bucle debería ser trivial desde aquí.

7

No utilice los sindicatos, Pavel aclara:

Es U.B., debido a que C++ prohíbe acceder a cualquier miembro de un sindicato que no sea el último que fue escrito a. En particular, el compilador es libre de optimizar distancia la asignación a int miembro a cabo completamente con el código anteriormente, dado que su valor no es utilizado posteriormente (que sólo ve el de lectura posterior para el miembro de char[4] , y tiene ninguna obligación de proporciona ningún valor significativo allí). En la práctica, g ++ en particular es conocido por tirar tales trucos, por lo que este no es solo teoría. Por otro lado, usando static_cast<void*> seguido de static_cast<char*> está garantizado al trabajo .

- Pavel Minaev

+1

Es U.B., porque C++ prohíbe el acceso a cualquier miembro de la unión que no sea el último en el que se escribió. En particular, el compilador es libre para optimizar la asignación de distancia a 'miembro int' a cabo completamente con el código de seguridad, ya que no se utiliza posteriormente su valor (que sólo ve la lectura posterior para el' char [4] 'miembro, y tiene ninguna obligación de proporcionar ningún valor significativo allí). En la práctica, g ++ en particular es conocido por sacar esos trucos, así que esto no es solo teoría. Por otro lado, el uso de '' static_cast seguido por '' static_cast se garantiza que funcione. –

+0

Pensé que, aunque nunca lo aclaré. Si no te importa, dejaré tu comentario como un consejo. – GManNickG

+0

No me importa, pero sería bueno arreglar esos 'static_cast's :) –

7
int main() { 
    typedef union foo { 
     int x; 
     char a[4]; 
    } foo; 

    foo p; 
    p.x = 0x01010101; 
    printf("%x ", p.a[0]); 
    printf("%x ", p.a[1]); 
    printf("%x ", p.a[2]); 
    printf("%x ", p.a[3]); 

    return 0; 
} 

Tenga en cuenta que el a [0] sostiene el LSB y una [3] sostiene el MSB, en una pequeña máquina endian.

+0

Su comentario sobre el LSB y el MSB solo es válido para pequeñas arquitecturas endian. –

+5

La lectura de 'p.a' en este código invoca U.B., porque no fue precedida por una escritura en' a'. Cualquier implementación de C++ conforme puede legalmente optimizar la asignación a 'p.x' por completo, y algunos lo harán. –

+0

Umm, sí y no. El resultado exacto es U.B., supongo, porque depende de la arquitectura de la plataforma, pero los sindicatos son la forma legal de alias diferentes tipos y me sorprendería bastante un compilador que no entendía totalmente que p.a había sido escrito. De hecho, los sindicatos son la * única * forma oficial de optimizar el aliasing en las implementaciones de gnu. – DigitalRoss

8
#include <stdio.h> 

int main(void) { 
    char a[sizeof(int)]; 
    *((int *) a) = 0x01010101; 
    printf("%d\n", *((int *) a)); 
    return 0; 
} 

tener en cuenta:

Un puntero a un objeto o tipo incompleto se puede convertir en un puntero a una objeto diferente o tipo incompleto. Si el puntero resultante no está alineado correctamente para el tipo apuntado , el comportamiento no está definido.

+3

El puntero se puede convertir, pero eso no significa que se pueda desreferenciar. P.ej. puedes convertir 'int *' a 'float *' (no U.B.), pero tan pronto como trates de escribir algo a través de 'float *', tocas U.B. Su ejemplo está bien porque la escritura a través de 'char *' está específicamente permitida para los POD, y la vida útil del POD se inicia tan pronto como se asigna memoria, pero vale la pena aclararlo. –

+2

En realidad, lo siento, estoy equivocado, y este ejemplo sigue siendo U.B. - Específicamente, no hay garantía de que 'a' esté alineado correctamente para' int'. Existe una garantía al asignar matrices con 'new', que se alinearán correctamente para cualquier objeto del mismo tamaño que array; pero no hay tal garantía para variables automáticas o estáticas, o campos de miembros. P.ej. considerar las declaraciones de variables locales: 'char c; char a [4]; '- hay una buena probabilidad de que 'a' no se asigne en un límite de 4 bytes, y en algunas arquitecturas esto provocará un bloqueo cuando intente escribir en esa ubicación mediante un' int * '. –

+0

Pavel, ¿podría aclarar qué quiere decir con POD y U.B.? Gracias – Polaris878

8

Nota: El acceso a una unión a través de un elemento que no fue el último asignado es un comportamiento indefinido. (suponiendo una plataforma donde los personajes son 8 bits y enteros son 4 bytes) Una máscara de bits de 0xFF será enmascarar un carácter tan

char arr[4]; 
int a = 5; 

arr[3] = a & 0xff; 
arr[2] = (a & 0xff00) >>8; 
arr[1] = (a & 0xff0000) >>16; 
arr[0] = (a & 0xff000000)>>24; 

haría arr [0] sostener el byte más significativo y la matriz [3] sostener lo menos.

de edición: Para que lo entienda el truco & es poco prudente 'y' donde como & & es lógico 'y'. Gracias a los comentarios sobre el turno olvidado.

+0

+1, ese es el camino a seguir si se requiere una representación binaria específica (es decir, sin confusión LSB/MSB). –

+4

¡No te olvides de cambiar! – Polaris878

+1

Como ha señalado Polaris878, los 3 últimos asignaciones establecerán '0' en la matriz, ya que no han utilizado ">>" en los valores. –

3

También puede utilizar la colocación de nuevo para esto:

void foo (int i) { 
    char * c = new (&i) char[sizeof(i)]; 
} 
0
 
union value { 
    int i; 
    char bytes[sizof(int)]; 
}; 

value v; 
v.i = 2; 

char* bytes = v.bytes; 
+1

Agregar alguna explicación a su respuesta ayuda a entender al lector. –

1
 

    #include <stdint.h> 

    int main(int argc, char* argv[]) { 
     /* 8 ints in a loop */ 
     int i; 
     int* intPtr 
     int intArr[8] = {1, 2, 3, 4, 5, 6, 7, 8}; 
     char* charArr = malloc(32); 

     for (i = 0; i < 8; i++) { 
      intPtr = (int*) &(charArr[i * 4]); 
      /*^  ^^ ^ */ 
      /* point at  | |  |  */ 
      /*  cast as int* |  |  */ 
      /*    Address of |  */ 
      /*   Location in char array */ 

      *intPtr = intArr[i]; /* write int at location pointed to */ 
     } 

     /* Read ints out */ 
     for (i = 0; i < 8; i++) { 
      intPtr = (int*) &(charArr[i * 4]); 
      intArr[i] = *intPtr; 
     } 

     char* myArr = malloc(13); 
     int myInt; 
     uint8_t* p8; /* unsigned 8-bit integer */ 
     uint16_t* p16; /* unsigned 16-bit integer */ 
     uint32_t* p32; /* unsigned 32-bit integer */ 

     /* Using sizes other than 4-byte ints, */ 
     /* set all bits in myArr to 1   */ 
     p8 = (uint8_t*) &(myArr[0]); 
     p16 = (uint16_t*) &(myArr[1]); 
     p32 = (uint32_t*) &(myArr[5]); 
     *p8 = 255; 
     *p16 = 65535; 
     *p32 = 4294967295; 

     /* Get the values back out */ 
     p16 = (uint16_t*) &(myArr[1]); 
     uint16_t my16 = *p16; 

     /* Put the 16 bit int into a regular int */ 
     myInt = (int) my16; 

    } 

1
char a[10]; 
int i=9; 

a=boost::lexical_cast<char>(i) 

encontraron esta es la mejor manera de convertir carbón en int y viceversa.

alternativa para impulsar :: lexical_cast es sprintf.

char temp[5]; 
temp[0]="h" 
temp[1]="e" 
temp[2]="l" 
temp[3]="l" 
temp[5]='\0' 
sprintf(temp+4,%d",9) 
cout<<temp; 

salida sería: hell9

Cuestiones relacionadas