【问题标题】:How do I get an address in C?如何在 C 中获取地址?
【发布时间】:2009-08-03 00:45:15
【问题描述】:

这可能有一个非常简单的答案,但我就是看不到。

#include <stdio.h>

int main(void) {
int x = 0;
printf("\n%d\n%d\n",x,&x);
}

好的,所以 printf 给出了 0 (x) 和 2293752 (&x)。我试图找出一种方法来查看任何地址 (&) 并查看已经存储在那里的内容。这只是为了实验。有什么帮助吗?

【问题讨论】:

  • 我建议你使用 %p 而不是 %d。它给你十六进制地址。
  • %p 用于void*,因此需要演员表。顺便说一句,该标准不保证它将以十六进制打印。
  • 不,它没有,但我还没有绊倒一个没有的实现。当然,现代本地 PDP-11 C 编译器可能会选择八进制,因为这是 PDP-11 上所有内容的自然表示。但是,我使用的 PDP 的最后一个本地 C 编译器 (DECUS C) 太旧了,无法使用 %p。

标签: c pointers memory-address


【解决方案1】:
void* memAddr = (void*)0xAABBCCDD; //put your memory address here
printf("int value at memory address %p is %i", memAddr, *((int*)memAddr));

您可能会发现检查任意内存地址只会导致崩溃。

【讨论】:

  • 测试过,是的,它只是崩溃了。我真的不需要知道任何地方有什么,我只是好奇。
  • 您假设 memAddr 包含一个 int,即 4 个字节。你至少应该使用无符号整数,因为你同样有可能让它看起来是负数。将字符转换为具有十六进制等可读格式的字符更合理。
  • 地址可以包含任何内容并可以转换为任何内容。例如:您假设 memAddr 包含一个无符号字符,它是一个字节。您至少应该使用带符号的字符,因为它实际上可能是一个负数。将 int 转换为诸如十进制等可读格式更合理。
【解决方案2】:

那将是指针解引用,即 * 运算符。但是,对于随机地址,您无法知道存储数据的 type 是什么。

#include <stdio.h>

int main(void) {
int x = 0;
printf("\n%d\n%d\n%d\n",x,&x,*(&x));
}

/* resulting output will be 0, some memory address, and 0 again */

【讨论】:

  • 不是我的意思。如果2293752是x的地址,那么我想检查0000000..99999999的地址是什么。
  • 请注意,*(&x) 实际上是将 * 运算符应用于值 (&x)。您可以改为将其应用于不涉及 & 运算符的内容 - 例如,常量地址。
  • 您会发现 GCC 在运行时中止了程序。在这些情况下非常严格,因此您最好先使用正确的%p 并转换为void*
  • 同意——不管怎样,随意胡闹内存通常效率不高。
  • 再次假设内存是一个 int。
【解决方案3】:

尝试这样做会遇到很多问题,首先,正如 Wilson 所提到的,您真的不知道那里存储了什么。

不过,Wilson 有点不对劲,您确实应该将其转换为 char 而不是 int,因为使用 int 您会看到 4 个字节,而不是像使用 char 那样的单个字节。

此外,除非您可以阅读 8 位 ASCII 字符并将它们映射到您脑海中有意义的东西,否则您可能希望将其转换为其他形式,例如 base2、base8 或 base16。

您可以通过多种方式做到这一点 - 最好的方法可能是使用按位运算符和二进制移位运算符,查找调度表以将其映射为可查看的 ASCII。

但是,您仍然不知道它在那里存储了什么,您只能看到原始二进制数据的某种编码形式。原因是 C 仅针对指向该内存地址的变量进行类型化。对该内存的裸视图只会为您提供二进制文件,而无法查找内存绑定到哪些变量或这些变量是什么类型。

第二个问题是您需要小心只查看您可以访问的部分内存。除非您小心访问它的方式,否则无法查看内存的代码段。如果您四处寻找以避免分段错误,您将很幸运。

不过,查看进程内存的最有效方法可能是将其段转储到磁盘。在 UNIX 中,这是通过核心转储完成的。然后,您可以在调试器上加载它并查看您心中的内容,甚至能够将其映射到具有足够堆栈知识的正确类型。您还可以使用二进制编辑器以无类型的方式检查它 - 通常字符串是可识别的。

祝你好运!

【讨论】:

    【解决方案4】:

    如果你想探索内存,我建议使用低级调试器,例如OllyDbg

    【讨论】:

      【解决方案5】:

      假设您想查看“原始”数据并且您知道进程地址空间内的地址,您可以这样做:

      long x=<address>
      printf("%x", *(int *)x);
      

      【讨论】:

      • 你能解释一下这部分吗:*(int *)x
      • -1:整数和指针在 C 中确实是不同的类型:AFAIK 不能保证 long 可以保存地址,而且我认为无论如何使用指针要明确得多。跨度>
      • 巴斯蒂安:触摸。事实上,这段代码非常依赖于硬件。没有真正的便携式(和安全/可靠)的方式来做原始海报想要的。 akway: *(int *)x 将变量 x 转换为指向整数的指针,然后检索存储在该指针指向的位置的(整数)值。它有效地将 x 的值视为指向整数的内存地址并读取该整数。如果该地址超出进程的地址空间,它将失败(以环境相关的方式)。
      【解决方案6】:

      要查看地址,您可以使用 %p

      printf("%p",&x);
      

      我建议你开始阅读指针,指针是一个存储内存地址的变量

      int x=10;
      int *p; //this is a pointer to int
      p=&x; //now p has the memory location of x
      printf("%d\n",*p); //this will print 10
      

      【讨论】:

        猜你喜欢
        • 2012-02-24
        • 1970-01-01
        • 1970-01-01
        • 2017-01-26
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2016-04-07
        • 1970-01-01
        相关资源
        最近更新 更多