2010-03-04 6 views
22

Предположим, что я делаюКак распечатать содержимое памяти переменной в C?

double d = 234.5; 

Я хочу видеть содержимое памяти d [целых 8 байт]

Как я могу это сделать?

+0

В какой форме вы хотите его увидеть? – danben

+8

почему вы думаете, что это восемь байт? –

+3

Я считаю, что поплавки * обычно * четыре байта, а удваиваются * обычно * восемь байтов. – Dolph

ответ

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]); 

Все методы показывают Вам байты — но то же double значение может напечатать байты по-разному в разных системах, например, из-за различных кодировок (редко), или иной порядок байтов.

+0

Я бы использовал указатель лично, но союз стал еще лучше imo. Хороший. Я, как правило, забываю об этом. – Xorlev

+0

Xorlev: Технически метод объединения не гарантирован для работы, тогда как существуют два других метода. – caf

+0

@caf: почему вы говорите, что метод объединения не гарантированно работает? До тех пор, пока в объединении используется массив 'unsigned char', он должен работать. –

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

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

@Craig: 'sizeof d' верен, я не знаю, почему вы изменили его на' sizeof (d) '(это также работает, но многие люди, такие как' sizeof d', когда 'd' не являются типом). –

+4

Согласен - я предпочитаю, чтобы он четко указывал, что это оператор, а не функция (я тоже не делаю 'return (x);') – caf

+4

Легче просто использовать круглые скобки, чтобы не хранить один _more_ вещь в этом сером вопросе наверху :-) Я _do_ предпочитаю использовать переменную, а не тип, если тип переменной когда-либо изменяется, поэтому мне не нужно менять столько кода. – paxdiablo

1

ли вы попробовать принимать адрес d и печать sizeof(d) байтов, начиная с этого адреса?

2

Попробуйте

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

Хотя решение является интересным, вы должны преобразовать его в C в этом случае. –

+0

и для полной переносимости вы должны использовать 'unsigned char data [sizeof (double)];' –

+0

Если я ошибаюсь, доступ к объединению через два разных члена приводит к неопределенному поведению. С другой стороны, я думаю, что если новый член имеет значения ловушки, но у char нет. – GManNickG

2

Если вы хотите, чтобы просмотреть это с помощью GDB Вы можете оформить:

x /gx d 

Г будет выводить значение как гигантская (8 байт)

1

использование дружественного отладчика - лучший способ увидеть значение местоположения памяти, то есть, если вы просто хотите увидеть.

2

Если вы хотите напечатать двойные значения в битах, попробуйте это. Я попытался оценить значение float. Если вы изменили это, вы сможете просмотреть двойное значение в 64 бит.

#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

Предоставлено моей библиотеки полезных сниппетов, вот решение в C, в комплекте с тестовым жгутом, и обеспечивая как шестнадцатеричный и 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; 
} 

Выход на моей системе является:

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            . 

Поскольку этот вопрос помечен C++ тоже, вот версия iostream для сравнения. Даже если вы не являетесь частным поклонником iostreams, он все равно подходит, если вы уже используете их. Возможность использования hexdump(any_obj) тоже хороша, но, конечно, может быть выполнена только с шаблоном делегирования функций, аналогичным 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

Поскольку этот вопрос отмечен как C++, версия iostream для сравнения: http://codepad.org/trVz9mlQ. Я не являюсь частным поклонником iostreams, но он подходит, если вы уже используете их. Возможность использования 'hexdump (any_obj)' тоже хороша (но, конечно, это может быть сделано только с шаблоном делегирования функций, подобным этому ctor). – 2010-03-04 07:44:06

+0

@Roger, я собирался включить этот код в этот ответ (с указанием, конечно, и предположение, что, если вы разместите свой собственный ответ, я удалю его из себя). Это потому, что я предпочитаю, чтобы SO по-прежнему был полезен, даже если все остальные сайты на планете (например, кодека) исчезли. Однако, видя, что ваша политика в отношении авторских прав на вашей странице пользователя SO дала мне паузу - никто не может использовать ваш код, если вы сохраняете авторские права, это бесполезно, кроме как для образования. Из-за этого я предпочел бы, чтобы вы опубликовали его как правильный ответ, а не комментарий со ссылкой, но это полностью зависит от вас. – paxdiablo

+0

Думал, что это больше связано с вашим ответом, чем стоило отдельного, и пространство комментариев ограничено, поэтому я просто рефлексивно дошел до кододела. Я отредактирую вопрос, чтобы включить его, тогда я стану его под лицензией SO. Повторно редактируйте, как вам нравится. - FWIW, хотя я думаю, что вы сейчас это понимаете, я только повторяю «дефолт», упоминая в своей биографии, что код, опубликованный в другом месте, не распространяется на лицензию SO, но я предполагал, что это будет больше дольше, тривиальный код, чем о коротких пачках codepad.org. – 2010-03-04 09:07:05

0

Я думаю, вы можете использовать операцию переключения и маску для «маскировки» фактических бит.

int t = 128;

для (INT I = 0; я < 8; ++ я) { Е ("% d", р & т);

p = >> 1;

t = >> 1; }

Смежные вопросы