2010-03-04 8 views

Respuesta

20
double d = 234.5; 

/* 1. use a union */ 
union u { 
    double d; 
    unsigned char c[sizeof(double)]; 
}; 
union u tmp; 
size_t i; 
tmp.d = d; 
for (i=0; i < sizeof(double); ++i) 
    printf("%02x\n", tmp.c[i]); 

/* 2. memcpy */ 
unsigned char data[sizeof d]; 
size_t i; 
memcpy(data, &d, sizeof d); 
for (i=0; i < sizeof d; ++i) 
    printf("%02x\n", data[i]); 

/* 3. Use a pointer to an unsigned char to examine the bytes */ 
unsigned char *p = (unsigned char *)&d; 
size_t i; 
for (i=0; i < sizeof d; ++i) 
    printf("%02x\n", p[i]); 

Todos los métodos que muestran la bytes — pero el mismo valor double pueden imprimir los bytes de manera diferente en diferentes sistemas, por ejemplo, debido a las diferentes codificaciones (raros), o diferente endianness.

+0

Hubiera usado un puntero personalmente, pero una unión es aún mejor. Buena esa. Tiendo a olvidarme de eso. – Xorlev

+0

Xorlev: Técnicamente, el método de unión no está garantizado para funcionar, mientras que los otros dos métodos sí lo están. – caf

+0

@caf: ¿por qué dices que no se garantiza que el método de unión funcione? Siempre que uno use la matriz 'unsigned char' en la unión, debería funcionar. –

26
unsigned char *p = (unsigned char *)&d; 
int i; 

for (i = 0; i < sizeof d; i++) 
    printf("%02x ", p[i]); 
+3

@Craig: 'sizeof d' es correcto, no sé por qué lo cambiaste a' sizeof (d) '(esto también funciona, pero a mucha gente le gusta' sizeof d' cuando 'd' no es un tipo). –

+4

De acuerdo - Prefiero dejar en claro que es un operador, no una función (no hago 'return (x);' tampoco) – caf

+4

Es más fácil usar siempre paréntesis para no tener que almacenar uno _more_ Lo que pasa en ese asunto gris arriba :-) Prefiero usar una variable en lugar de un tipo en caso de que el tipo de la variable cambie alguna vez, así que no tengo que cambiar tanto código. – paxdiablo

1

¿Usted intentó tomar la dirección de d e imprimir sizeof(d) bytes a partir de esa dirección?

2

Trate

union Plop 
{ 
    double value; 
    char  data[sizeof(double)]; 
}; 

Plop print; 
print.value = 234.5; 

std::copy(print.data,print.data+sizeof(double),std::ostream_iterator<int>(std::cout)," "); 
std::cout << std::endl; 
+0

Si bien la solución es interesante, debería convertirla a C en este caso. –

+0

y para ser totalmente portátil, debe usar 'datos de caracteres sin signo [sizeof (double)];' –

+0

A menos que esté equivocado, acceder a una unión a través de dos miembros diferentes conduce a un comportamiento indefinido. Por otra parte, creo que fue si el nuevo miembro tiene valores trap, pero char no tiene ninguno. – GManNickG

2

Si usted está mirando para ver esto desde GDB puede emitir:

x /gx d 

El g imprimirá el valor como un gigante (8 bytes)

1

Usar su amigable depurador es la mejor manera de ver el valor de la ubicación de la memoria, es decir, si solo desea ver.

2

Si desea imprimir los valores dobles en bits, intente esto. He intentado con el valor flotante. Si cambió eso, puede ver el valor doble en 64 bits.

#include <stdio.h> 

int main (void) 
{ 
     float f = 10.0f; 

     struct Float { 
       unsigned char bit01:1; 
       unsigned char bit02:1; 
       unsigned char bit03:1; 
       unsigned char bit04:1; 
       unsigned char bit05:1; 
       unsigned char bit06:1; 
       unsigned char bit07:1; 
       unsigned char bit08:1; 
       unsigned char bit09:1; 
       unsigned char bit10:1; 
       unsigned char bit11:1; 
       unsigned char bit12:1; 
       unsigned char bit13:1; 
       unsigned char bit14:1; 
       unsigned char bit15:1; 
       unsigned char bit16:1; 
       unsigned char bit17:1; 
       unsigned char bit18:1; 
       unsigned char bit19:1; 
       unsigned char bit20:1; 
       unsigned char bit21:1; 
       unsigned char bit22:1; 
       unsigned char bit23:1; 
       unsigned char bit24:1; 
       unsigned char bit25:1; 
       unsigned char bit26:1; 
       unsigned char bit27:1; 
       unsigned char bit28:1; 
       unsigned char bit29:1; 
       unsigned char bit30:1; 
       unsigned char bit31:1; 
       unsigned char bit32:1; 
     }; 

     struct Float *F; 

     F = (struct Float *) &f; 

     printf("\nMSB -->1 bit for sign bit; 8 bit for exponent; 23 bit for mantisa<-- LSB\n"); 
     printf("%d ", F->bit32); 
     printf("%d", F->bit31); 
     printf("%d", F->bit30); 
     printf("%d", F->bit29); 
     printf("%d", F->bit28); 
     printf("%d", F->bit27); 
     printf("%d", F->bit26); 
     printf("%d", F->bit25); 
     printf("%d ", F->bit24); 
     printf("%d", F->bit23); 
     printf("%d", F->bit22); 
     printf("%d", F->bit21); 
     printf("%d", F->bit20); 
     printf("%d", F->bit19); 
     printf("%d", F->bit18); 
     printf("%d", F->bit17); 
     printf("%d", F->bit16); 
     printf("%d", F->bit15); 
     printf("%d", F->bit14); 
     printf("%d", F->bit13); 
     printf("%d", F->bit12); 
     printf("%d", F->bit11); 
     printf("%d", F->bit10); 
     printf("%d", F->bit09); 
     printf("%d", F->bit08); 
     printf("%d", F->bit07); 
     printf("%d", F->bit06); 
     printf("%d", F->bit05); 
     printf("%d", F->bit04); 
     printf("%d", F->bit03); 
     printf("%d", F->bit02); 
     printf("%d\n", F->bit01); 
} 
7

Cortesía de mi biblioteca de fragmentos útiles, he aquí una solución en C, con arnés de prueba, y proporcionando tanto hexagonal y datos ASCII:

#include <stdio.h> 

void hexDump (char *desc, void *addr, int len) { 
    int i; 
    unsigned char buff[17];  // stores the ASCII data 
    unsigned char *pc = addr;  // cast to make the code cleaner. 

    // Output description if given. 

    if (desc != NULL) 
     printf ("%s:\n", desc); 

    // Process every byte in the data. 

    for (i = 0; i < len; i++) { 
     // Multiple of 16 means new line (with line offset). 

     if ((i % 16) == 0) { 
      // Just don't print ASCII for the zeroth line. 

      if (i != 0) 
       printf (" %s\n", buff); 

      // Output the offset. 

      printf (" %04x ", i); 
     } 

     // Now the hex code for the specific character. 

     printf (" %02x", pc[i]); 

     // And store a printable ASCII character for later. 

     if ((pc[i] < 0x20) || (pc[i] > 0x7e)) 
      buff[i % 16] = '.'; 
     else 
      buff[i % 16] = pc[i]; 
     buff[(i % 16) + 1] = '\0'; 
    } 

    // Pad out last line if not exactly 16 characters. 

    while ((i % 16) != 0) { 
     printf (" "); 
     i++; 
    } 

    // And print the final ASCII bit. 

    printf (" %s\n", buff); 
} 

int main (int argc, char *argv[]) { 
    double d1 = 234.5; 
    char s1[] = "a 15char string"; 
    char s2[] = "This is a slightly longer string"; 
    hexDump ("d1", &d1, sizeof d1); 
    hexDump ("s1", &s1, sizeof s1); 
    hexDump ("s2", &s2, sizeof s2); 
    return 0; 
} 

La salida en mi sistema es:

d1: 
    0000 00 00 00 00 00 50 6d 40       [email protected] 
s1: 
    0000 61 20 31 35 63 68 61 72 20 73 74 72 69 6e 67 00 a 15char string. 
s2: 
    0000 54 68 69 73 20 69 73 20 61 20 73 6c 69 67 68 74 This is a slight 
    0010 6c 79 20 6c 6f 6e 67 65 72 20 73 74 72 69 6e 67 ly longer string 
    0020 00            . 

Dado que esta cuestión se marca C++ también, aquí está una versión iostream para comparar. Incluso si no eres un entusiasta de iostreams, aún cabe en si ya los estás usando. También es bueno poder usar hexdump(any_obj), pero por supuesto se puede hacer con solo una plantilla de función de delegación similar al ctor.

#include <iomanip> 
#include <ostream> 
#include <string> 

struct hexdump { 
    void const* data; 
    int len; 

    hexdump(void const* data, int len) : data(data), len(len) {} 

    template<class T> 
    hexdump(T const& v) : data(&v), len(sizeof v) {} 

    friend 
    std::ostream& operator<<(std::ostream& s, hexdump const& v) { 
    // don't change formatting for s 
    std::ostream out (s.rdbuf()); 
    out << std::hex << std::setfill('0'); 

    unsigned char const* pc = reinterpret_cast<unsigned char const*>(v.data); 

    std::string buf; 
    buf.reserve(17); // premature optimization 

    int i; 
    for (i = 0; i < v.len; ++i, ++pc) { 
     if ((i % 16) == 0) { 
     if (i) { 
      out << " " << buf << '\n'; 
      buf.clear(); 
     } 
     out << " " << std::setw(4) << i << ' '; 
     } 

     out << ' ' << std::setw(2) << unsigned(*pc); 
     buf += (0x20 <= *pc && *pc <= 0x7e) ? *pc : '.'; 
    } 
    if (i % 16) { 
     char const* spaces16x3 = "            "; 
     out << &spaces16x3[3 * (i % 16)]; 
    } 
    out << " " << buf << '\n'; 

    return s; 
    } 
}; 

int main() { 
    std::cout << "double:\n" << hexdump(234.5); 
    std::cout << "string 1:\n" << hexdump("a 15char string"); 
    std::cout << "string 2:\n" << hexdump("This is a slightly longer string"); 

    return 0; 
} 
+0

Dado que esta pregunta también está etiquetada con C++, la versión de iostream se puede comparar: http://codepad.org/trVz9mlQ. No soy un fanático particular de iostreams, pero encaja si ya los estás usando. También es bueno poder usar 'hexdump (any_obj)' (pero, por supuesto, se puede hacer con una plantilla de función de delegado similar a la de ese ctor). –

+0

@Roger, iba a incorporar ese código en esta respuesta (con la atribución, por supuesto, y la sugerencia de que si publicabas tu propia respuesta, la eliminaría de la mía). Eso es porque prefiero que SO siga siendo útil incluso si desaparecen todos los demás sitios del planeta (como el teclado numérico). Sin embargo, ver su política de derechos de autor en su página de usuario de SO me dio una pausa, nadie puede usar su código si usted mantiene los derechos de autor, es inútil que no sea para la educación. Por eso, preferiría que lo publicaras como una respuesta adecuada en lugar de un comentario con un enlace, pero es totalmente tu decisión. – paxdiablo

+0

Pensé que esto se relacionaba más con tu respuesta que valía la pena por separado, y el espacio para comentarios es limitado, así que simplemente busqué reflexivamente el teclado. Editaré la pregunta para incluirla, luego seré yo quien la coloque bajo la licencia de SO. Vuelve a editar como quieras - FWIW, aunque creo que ahora te das cuenta, solo estoy repitiendo "el valor predeterminado" al mencionar en mi biografía que el código publicado en otro lugar no está cubierto por la licencia de SO, pero tenía la intención de ser más sobre el tiempo, menos código trivial que sobre pastas cortas de codepad.org. –

0

Creo que puede usar la operación de cambio y la máscara para "enmascarar" los bits reales.

int t = 128;

for (int i = 0; i < 8; ++ i) { printf ("% d", p & t);

p = >> 1;

t = >> 1; }

Cuestiones relacionadas