【问题标题】:Display contents (in hex) of 16 bytes at the specified address显示指定地址的 16 字节内容(十六进制)
【发布时间】:2018-03-12 20:09:39
【问题描述】:

我正在尝试显示特定地址的内容,给该地址一个 char*。到目前为止,我已经尝试使用以下实现来做到这一点

int mem_display(char *arguments) {
    int address = *arguments; 
    int* contents_pointer = (int*)address;
    int contents = *contents_pointer;
    printf("Address %p: contents %16x\n", contents_pointer, contents);              
}

但我不断收到“分段错误(核心转储)”错误。我试图制作一个虚拟指针来测试

char foo = 6;  
char *bar = &foo;

但错误仍然存​​在

【问题讨论】:

    标签: c++ c pointers hex memory-address


    【解决方案1】:

    长期以来,我使用以下功能打印内存区域的内容:

    /*************************************************************/
    /**
      * Function to dump memory area
      * \param address     start address
      * \param len         length of memory area
      */
    /*************************************************************/
    void dump( void* address, int len ) noexcept{
        int i;
      printf("dump from 0x%lX (%d bytes)\n",(long)address, len);
      printf("=============================================");
      for(i=0; i<len; i++){
        if(i%16==0){printf("\n");}
         printf("%2X ",(*((char*)address+i))&0xFF);
      }
      printf("\n=============================================\n");
    }
    

    对于 C 程序,删除 noexcept 关键字。

    【讨论】:

      【解决方案2】:

      我认为您要么过于复杂,要么没有充分描述实际输入是什么。是指向指针的指针吗?

      无论如何,要通过一些指向内存的指针以简单的方式执行此操作,例如(C-like C++,抱歉,在 web cpp.sh 上匆忙在线完成):

      #include <iostream>
      
      const unsigned char fakeData[] = { 1, 13, 0, 255 };
      
      void mem_display(
          std::FILE* file,
          const unsigned char* memoryPtr,
          const size_t size)
      {
          fprintf(file, "Address %p:", (const void*)memoryPtr);
          for (size_t i = 0; i < size; ++i) fprintf(file, " %02hhx", memoryPtr[i]);
          fprintf(file, "\n");
      }
      
      
      int main()
      {
          mem_display(stdout, fakeData, 4);
      }
      

      输出:

      Address 0x4008e6: 01 0d 00 ff
      

      要打印 16 个字节,只需更改 size 参数即可。

      我想不出有 16 个字节的通用类型,所以我不确定你为什么要尝试将其打印为单个数字,通常像上面这样的单字节输出在调试器中使用(直到用户请求不同的大小单位)。

      【讨论】:

        【解决方案3】:

        如果您已经有一个指向要打印其内容的地址的指针,您可以将其直接提供给printf,如下所示:

        void print_16_bytes_at(const char *arguments)
        {
           printf("Address %p: contents", (const void *)arguments);
           for (int i = 0; i < 16; i++)
               printf(" %02x", (unsigned int)(unsigned char)arguments[i]);
           putchar('\n');
        }
        

        如果arguments 不是指向要打印其内容的内存的指针,那么我不明白它实际上是什么,我需要你更好地解释一下。 p>

        以上示例代码注意事项:

        1. 要使用%p 而不引起未定义的行为,您必须将指针显式转换为[const] void *,除非它已经是[const] void *。因为printf 采用可变数量的参数,编译器不知道其参数的预期类型,因此它不会为您插入此转换,就像使用带有[const] void * 参数的普通函数一样。
        2. 双重转换(unsigned int)(unsigned char) 强制从arguments[i] 读取的char 进行零扩展,而不是符号扩展至unsigned int 的宽度。如果您不这样做,则从 0x80 开始的值可能会打印出一堆前导 F(例如 ffffff80),这可能不是您想要的。
        3. 如果在提供的地址上没有 16 字节的可读内存,这仍然会出现段错误。在你的例子中

          char foo = 6;
          print_16_bytes_at(&foo);
          

          foo 地址处只能保证有一个 字节的可读内存。 (它可能适用于您可以轻松使用的任何计算机,但根据 C 标准的字母,它仍然允许崩溃。)

        【讨论】:

          【解决方案4】:

          原始代码存在一些问题。首先,它间接两次传入的指针。它将arguments 视为指向要打印的内容的指针。由于arguments 是指向char 的指针,这绝对是错误的。 (它最终会从一个非常小的地址读取,这在大多数架构上是明确的分段违规或其他崩溃。)

          其次,除非您知道 arguments 指针已正确对齐,否则通过该指针加载 int 可能会由于未对齐的访问而崩溃。 (这很可能会显示为分段违规。)您可能无法假设此例程正确对齐。

          第三,如果您需要打印 16 个字节,那么 int 将(通常)只得到 4 或 8 个。使用标准打印例程连接所有部分比逐字节循环写入要棘手。 (有关此类循环的示例,请参见上面的答案。)

          【讨论】:

          • 它甚至不是一个指针到指针;代码将address 处的第一个字节 视为指针值。
          【解决方案5】:

          您需要遍历地址的内容,并分别打印每个内容,直到达到 16。示例代码:

          #include <stdio.h>
          
          void mem_display(unsigned char *arguments) {
              printf("Address %p: ", arguments);
              int i =0;
              unsigned char* byte_array = arguments;
              while (i < 16)
              {
                  printf("%02hhx", byte_array[i]);
                  i++;
              }            
          }
          
          int main(void) {
              unsigned char foo = 6;  
              unsigned char *bar = &foo;
              mem_display(bar);
          
              return 0;
          }
          

          输出:

          地址 0x7ffe5b86a777: 0677A7865BFE7F000060054000000000

          【讨论】:

            【解决方案6】:

            我发现很难解释问题出在哪里,因为您的代码中几乎每一行都是错误的。

            我会这样做:

            void mem_display(const void *address) {
                const unsigned char *p = address;
                for (size_t i = 0; i < 16; i++) {
                    printf("%02hhx", p[i]);
                }
                putchar('\n');
            }
            

            【讨论】:

            • @gsamaras 因为这是unsigned char(十六进制)的 printf 格式。
            • 您不需要将void* 转换为char* 吗?
            • @BarmakShemirani 不在 C 语言中。不幸的是,OP 用 C 和 C++ 标记了他的问题。
            猜你喜欢
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2013-01-11
            • 1970-01-01
            • 2017-09-13
            • 2012-01-08
            • 1970-01-01
            相关资源
            最近更新 更多