29

Suppose I do a

double d = 234.5;

I want to see the memory contents of d [the whole 8 bytes]

How do I do that?

Lazer
  • 90,700
  • 113
  • 281
  • 364

9 Answers9

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

for (i = 0; i < sizeof d; i++)
    printf("%02x ", p[i]);
caf
  • 233,326
  • 40
  • 323
  • 462
  • 3
    @Craig: `sizeof d` is correct, I don't know why you changed it to `sizeof(d)` (this also works, but many people like `sizeof d` when `d` is not a type). – Alok Singhal Mar 04 '10 at 05:40
  • 4
    Agreed - I prefer to keep it clear that it's an operator, not a function (I don't do `return(x);`, either) – caf Mar 04 '10 at 05:59
  • 4
    It's easier to just always use parentheses so as to not have to store one _more_ thing in that grey matter upstairs :-) I _do_ prefer using a variable rather than a type in case the type of the variable ever changes, so I don't have to change as much code. – paxdiablo Mar 04 '10 at 06:09
21
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]);

All the methods show you the bytes—but the same double value may print the bytes differently on different systems, e.g., due to different encodings (rare), or different endianness.

Alok Singhal
  • 93,253
  • 21
  • 125
  • 158
  • I'd have used a pointer personally, but a union is even better imo. Nice one. I tend to forget about it. – Xorlev Mar 04 '10 at 05:38
  • Xorlev: Technically the union method is not guranteed to work, whereas the other two methods are. – caf Mar 16 '10 at 22:56
  • @caf: why do you say that the union method is not guaranteed to work? As long as one uses `unsigned char` array in the union, it should work. – Alok Singhal Mar 16 '10 at 23:06
  • Annex J of the C standard lists "The value of a union member other than the last one stored into" as being "unspecified", and it is this that I was thinking of. However I don't believe the Annex is normative, and I cannot find a normative reference that says the same thing, so the Annex may be in error. – caf Mar 16 '10 at 23:36
  • @caf, thanks. Footnote 82 says: If the member used to access the contents of a union object is not the same as the member last used to store a value in the object, the appropriate part of the object representation of the value is reinterpreted as an object representation in the new type as described in 6.2.6 (a process sometimes called "type punning"). This might be a trap representation. But that's non-normative as well. From my reading of a lot of messages on comp.lang.c, it seems like people there think this particular method (`unsigned char` in a union) is allowed. – Alok Singhal Mar 17 '10 at 00:12
9

Courtesy of my library of useful snippets, here's a solution in C, complete with test harness, and providing both hex and ASCII data:

#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;
}

The output on my system is:

d1:
  0000  00 00 00 00 00 50 6d 40                          .....Pm@
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                                               .

Since this question is tagged C++ too, here's an iostream version to compare. Even if you're not a particular fan of iostreams, it still fits in if you're already using them. Being able to use hexdump(any_obj) is nice too, but of course can be done with just a delegating function template similar to the 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;
}
paxdiablo
  • 854,327
  • 234
  • 1,573
  • 1,953
  • Since this question is tagged C++ too, iostream version to compare: http://codepad.org/trVz9mlQ. I'm not a particular fan of iostreams, but it fits in if you're already using them. Being able to use `hexdump(any_obj)` is nice too (but of course can be done with just a delegating function template similar to that ctor). –  Mar 04 '10 at 07:44
  • @Roger, I was going to incorporate that code into this answer (with attribution of course, and the suggestion that if you posted your own answer, I would remove it from mine). That's because I prefer SO to still be useful even if every other site on the planet (such as codepad) disappeared. However, seeing your copyright policy on your SO user page gave me pause - no-one can use your code if you maintain the copyrights, it's useless other than for education. Because of that, I would prefer you post it as a proper answer rather than a comment with a link, but it's totally up to you. – paxdiablo Mar 04 '10 at 08:53
  • Thought this related more to your answer than was worth a separate one, and comment space is limited so I just reflexively reached for codepad. I'll edit the question to include it, then I'll be the one placing it under SO's license. Re-edit as you like. -- FWIW, though I think you realize it now, I'm only restating "the default" by mentioning in my bio that code posted elsewhere isn't covered by SO's license, but I had intended that to be more about longer, less trivial code than about short codepad.org pastes. –  Mar 04 '10 at 09:07
2

Try

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;
Martin York
  • 257,169
  • 86
  • 333
  • 562
  • While the solution is interesting, you should convert it to C in this case. – Mikael S Mar 04 '10 at 04:49
  • and to be fully portable, you should use `unsigned char data[sizeof(double)];` – Alok Singhal Mar 04 '10 at 04:51
  • Unless I'm mistaken, accessing a union through two different members leads to undefined behavior. Then again, I think it was if the new member has trap values, but char has none. – GManNickG Mar 04 '10 at 05:09
  • 1
    @GMan: the standard makes an exception for unsigned char or unsigned char arrays in a union. – Alok Singhal Mar 04 '10 at 05:28
  • @Alok: Why unsigned? Is it just because it may print out double and be confusing or is there another reason? – Martin York Mar 04 '10 at 05:43
  • @Martin: I think that the standard allows `char` to have padding, but `unsigned char` cannot have padding. In other words, `data[i]` may not be a valid `char` value in your code above. I can't find the relevant section in the standard right now, but I am fairly sure it's there. :-) – Alok Singhal Mar 04 '10 at 06:04
  • @Alok: "For character types [it includes all 3 at this point], all bits of the object representation participate in the value representation." (3.9.1/1) No padding bits. –  Mar 04 '10 at 06:31
  • @Gman, @Alok: I was looking for the relevant union-member-access rules about storing one member and accessing another, but couldn't find them (nor any exceptions for character types). I think it might be tied up in the object lifetime (3.8) and not clearly spelled out for unions. –  Mar 04 '10 at 06:33
  • @Roger: 3.9.1p1 is from the C++ standard? Can't find something similar in the C standard. Maybe the languages are different in this regard? About union access, n1256 (C, not C++) 6.2.6.1p4 says: "Values stored in non-bit-field objects of any other object type consist of `n*CHAR_BIT` bits, where `n` is the size of an object of that type, in bytes. The value may be copied into an object of type `unsigned char [n]` (e.g., by `memcpy`); the resulting set of bytes is called the object representation of the value." ... – Alok Singhal Mar 04 '10 at 07:02
  • ... and Footnote 85 in 6.5.2.3 (*Structure and Union Members*) says: "If the member used to access the contents of a union object is not the same as the member last used to store a value in the object, the appropriate part of the object representation of the value is reinterpreted as an object representation in the new type as described in 6.2.6 (a process sometimes called "type punning"). This might be a trap representation." Again, this is all C, not C++. – Alok Singhal Mar 04 '10 at 07:03
  • @Alok, Sorry, yes, I forgot to specify C++ for those quotes (the question is tagged both), but did search both C and C++ for the union rules. I cannot find your quote from 6.5.2.3 (I'm using n1124 from http://www.open-std.org/jtc1/sc22/wg14/www/standards.html), but it's not clear to me that 6.2.6.1 makes any exception for union members. The C standard is included in C++ by 1.2, too, which is no end of confusion on exactly what rules apply. –  Mar 04 '10 at 07:59
  • That quoted footnote is 82, not 85, in n1256. –  Mar 04 '10 at 08:10
  • @Roger, sorry, I must have been dylsexic when I said 85 instead of 82. Basically I was saying that n1256 redirects one to 6.2.6 when accessing union members other than the last one modified, but as you said, n1124 doesn't have that quote. At this point, I don't know if I know what's actually guaranteed in this case :-). – Alok Singhal Mar 04 '10 at 08:25
2

If you're looking to view this from gdb you can issue:

x /gx d

The g will print the value as a giant (8 bytes)

nall
  • 15,899
  • 4
  • 61
  • 65
2

If you want to print the double values in bits try this. I have tried for float value. If you changed that you can be able to view the double value in 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);
}
Alok Singhal
  • 93,253
  • 21
  • 125
  • 158
sganesh
  • 1,731
  • 1
  • 13
  • 14
1

Did you try taking the address of d and print sizeof( d ) bytes starting from that address?

Arun
  • 19,750
  • 10
  • 51
  • 60
1

using your friendly debugger is the best way to see the value of the memory location, that is if u just want to see.

the100rabh
  • 4,077
  • 4
  • 32
  • 40
0

I think you can use shift operation and mask to "mask out" the actual bits.

int t = 128;

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

p =>> 1;

t =>> 1; }