tags:

views:

526

answers:

9

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?

+21  A: 
unsigned char *p = (unsigned char *)&d;
int i;

for (i = 0; i < sizeof d; i++)
    printf("%02x ", p[i]);
caf
@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
Agreed - I prefer to keep it clear that it's an operator, not a function (I don't do `return(x);`, either)
caf
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
+1  A: 

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

ArunSaha
+2  A: 

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
While the solution is interesting, you should convert it to C in this case.
Mikael S
and to be fully portable, you should use `unsigned char data[sizeof(double)];`
Alok
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.
GMan
@GMan: the standard makes an exception for unsigned char or unsigned char arrays in a union.
Alok
@Alok: I suspected as much, thanks.
GMan
@Alok: Why unsigned? Is it just because it may print out double and be confusing or is there another reason?
Martin York
@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
@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.
Roger Pate
@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.
Roger Pate
@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
... 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
@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.
Roger Pate
That quoted footnote is 82, not 85, in n1256.
Roger Pate
@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
+3  A: 

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
A: 

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
+6  A: 
Alok
I'd have used a pointer personally, but a union is even better imo. Nice one. I tend to forget about it.
Xorlev
Xorlev: Technically the union method is not guranteed to work, whereas the other two methods are.
caf
@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
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
@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
+1  A: 

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);
}
sganesh
wow. Yes, that would work I suppose? +1 for unique answer I guess lol
Polaris878
+3  A: 

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
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).
Roger Pate
@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
@paxdiablo: 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.
Roger Pate
A: 

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

Foxcat