【问题标题】:How to print out the memory contents of a variable in C?如何打印出C中变量的内存内容?
【发布时间】:2011-01-23 12:44:34
【问题描述】:

假设我做一个

double d = 234.5;

我想查看d的内存内容[整个8个字节]

我该怎么做?

【问题讨论】:

  • 你想看什么形式的?
  • 为什么你认为是8个字节?
  • 我相信浮点数通常四个字节,双精度通常八个字节。
  • 这是实现定义的。
  • 它的 sizeof(double) 取决于硬件和编译器选项。

标签: c++ c memory double


【解决方案1】:
unsigned char *p = (unsigned char *)&d;
int i;

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

【讨论】:

  • @Craig: sizeof d 是正确的,我不知道你为什么把它改成sizeof(d) (这也可以,但是很多人喜欢sizeof dd 不是一个类型)。
  • 同意 - 我更愿意明确表示它是一个运算符,而不是一个函数(我也不这样做 return(x);
  • 总是使用括号更容易,这样就不必在楼上的灰质中存储一个 more 的东西 :-) 我 do 更喜欢使用变量而不是类型以防变量的类型发生变化,因此我不必更改太多代码。
【解决方案2】:

您是否尝试获取d 的地址并从该地址开始打印sizeof( d ) 字节?

【讨论】:

    【解决方案3】:

    试试

    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;
    

    【讨论】:

    • 虽然解决方案很有趣,但在这种情况下,您应该将其转换为 C。
    • 为了完全便携,你应该使用unsigned char data[sizeof(double)];
    • 除非我弄错了,否则通过两个不同的成员访问联合会导致未定义的行为。再说一次,我认为如果新成员有陷阱值,但 char 没有。
    • @GMan:标准对联合中的无符号字符或无符号字符数组进行了例外处理。
    • @Alok:为什么没有签名?是因为它可能会打印出双倍并造成混淆还是有其他原因?
    【解决方案4】:

    如果您希望从 gdb 中查看此内容,您可以发出:

    x /gx d
    

    g 会将值打印为一个巨大的(8 个字节)

    【讨论】:

      【解决方案5】:

      使用友好的调试器是查看内存位置值的最佳方式,如果您只想查看。

      【讨论】:

        【解决方案6】:
        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 值可能会在不同系统上以不同方式打印字节,例如,由于不同的编码(罕见)或不同的字节序。

        【讨论】:

        • 我个人会使用指针,但在 imo 中联合更好。好东西。我倾向于忘记它。
        • Xorlev:从技术上讲,union 方法并不能保证有效,而其他两种方法可以。
        • @caf:为什么说union方法不能保证有效?只要在联合中使用unsigned char 数组,它应该可以工作。
        • C 标准的附录 J 将“存储到的最后一个以外的联合成员的值”列为“未指定”,这就是我的想法。但是我不相信附件是规范性的,而且我找不到说明相同内容的规范性参考资料,因此附件可能有误。
        • @caf,谢谢。脚注 82 说:如果用于访问联合对象内容的成员与上次用于在对象中存储值的成员不同,则该值的对象表示的适当部分将被重新解释为对象表示6.2.6 中描述的新类型(有时称为“类型双关语”的过程)。这可能是一个陷阱表示。但这也是不规范的。从我对 comp.lang.c 上的大量消息的阅读来看,那里的人似乎认为这种特殊方法(unsigned char in a union)是允许的。
        【解决方案7】:

        如果你想以位打印双精度值,试试这个。 我试过浮点值。 如果你改变了,你可以看到 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);
        }
        

        【讨论】:

          【解决方案8】:

          感谢我的有用 sn-ps 库,这是一个 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                          .....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                                               .
          

          因为这个问题也被标记为 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;
          }
          

          【讨论】:

          • 由于这个问题也被标记为 C++,所以要比较的 iostream 版本:codepad.org/trVz9mlQ。我不是 iostreams 的特别粉丝,但如果您已经在使用它们,它就很合适。能够使用hexdump(any_obj) 也很好(当然可以使用类似于该ctor 的委派函数模板来完成)。
          • @Roger,我打算将该代码合并到此答案中(当然要注明出处,并建议如果您发布自己的答案,我会将其从我的答案中删除)。那是因为即使地球上的所有其他站点(例如键盘)都消失了,我更喜欢 SO 仍然有用。但是,在您的 SO 用户页面上看到您的版权政策让我停下来——如果您维护版权,没有人可以使用您的代码,除了教育之外,它没有用处。因此,我希望您将其发布为正确的答案,而不是带有链接的评论,但这完全取决于您。
          • 认为这与您的答案相关的更多,而不是一个单独的答案,并且评论空间有限,所以我只是反射性地伸手去拿键盘。我将编辑问题以包含它,然后我将成为将其置于 SO 许可下的人。根据需要重新编辑。 -- FWIW,虽然我想你现在已经意识到了,我只是重申“默认”,在我的简历中提到发布在其他地方的代码不在 SO 的许可范围内,但我原本打算更多的是更长,更少比简短的 codepad.org 粘贴更简单的代码。
          【解决方案9】:

          我认为您可以使用移位操作和掩码来“屏蔽”实际位。

          int t = 128;

          for(int i=0;i

          p =>> 1;

          t =>> 1; }

          【讨论】:

            猜你喜欢
            • 2018-08-15
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2021-09-03
            • 2017-07-30
            • 2016-01-23
            • 2014-05-17
            • 1970-01-01
            相关资源
            最近更新 更多