【问题标题】:How to get the actual address of a pointer in C?如何在C中获取指针的实际地址?
【发布时间】:2010-04-28 01:17:53
【问题描述】:

背景:
我正在用 C 语言编写一个单级缓存模拟器来完成家庭作业,并且我得到了必须使用的代码。在我们对缓存的讨论中,我们被告知小缓存保存大地址的方法是将大地址拆分为缓存中的位置和一个标识标签。也就是说,如果你有一个 8 槽高速缓存但想存储地址大于 8 的东西,你取 3(因为 2^3=8)最右边的位并将数据放在那个位置;因此,如果您有地址 22,例如二进制 10110,您将采用最右边的 3 位 110,即十进制 5,并将其放入高速缓存的插槽 5。您还可以在此位置存储标签,即剩余的 10 位。

一个函数,cache_load,接受一个参数和整数指针。如此有效,我得到了这个 int* addr ,它是一个实际地址并指向某个值。为了将此值存储在缓存中,我需要拆分地址。但是,当我尝试直接使用指针时,编译器不喜欢。因此,例如,我尝试通过以下方式获得职位:
npos=addr%num_slots

编译器生气并给我错误。我尝试强制转换为 int,但这实际上让我得到了指针指向的值,而不是数字地址本身。任何帮助表示赞赏,谢谢!

[编辑]

int load(int * addr) { 
  int value = (use_memory ? (*addr) : 0);
  intptr_t taddr=(intptr_t) addr;
  int npos=taddr % blocks;
  int ntag=taddr / blocks;
  printf("addr is %p, taddr is %p, npos is %d and ntag is %d\n",addr,taddr,npos,ntag);

当 addr 传入时,它的实际地址是 58,它指向的值是 88。我从那个 printf 得到的输出是:

addr 为 58,taddr 为 58,npos 为 0,ntag 为 11

所以看起来 taddr 得到了 58(使用 %p 打印时,使用 %d 打印时仍然显示 88),但是 npos 和 ntag 显示为 0 和 11(好像数学运算正在使用 88 运行)而不是我想要的 2 和 7。

代码是这样使用的:

void load_words (int n, int words[]) {
  int i;
  for (i=0; i<n; i++) {
    load( (int *) (words[i] * 4));
    cache_print();
  }
}

【问题讨论】:

  • 将指针转换为 int 不会给您它指向的值。但是,您通常应该改为使用intptr_t。另外,请发布一些实际代码。
  • 我现在放了一些代码,以及我得到的输出。我希望 taddr 与 addr (58) 相同,以便可以在其上使用模数和除法运算符。 edit 另外,如果我尝试这样转换,我会得到“`intptr_t' undeclared (first use in this function)”。
  • blocks 只是一个整数。我刚刚用新的输出更新了原始帖子中的代码。
  • @Airjoe 呵呵。初学者错误:%p 以十六进制(以 16 为底)而不是像 %d 那样以十进制(以 10 为底)打印。
  • 那个 pastebin 链接是我教授给我的“好”代码,是的。我有一种强烈的感觉,我的教授可能跑题了,因为他通常是一名 Java 教授,而这个学期正在教授低级计算机组织课程。我真的不明白他为什么不使用 & 或者他为什么要乘以 4。现在,我将把它标记为已解决,直到我与他讨论。谢谢大家的帮助,时间很抱歉。

标签: c


【解决方案1】:

C99 标准规定,从指针类型到整数类型或反之亦然的转换是实现定义的行为(6.3.2.3.5 和 6.3.2.3.6),除非使用 intptr_tuintptr_t&lt;stdint.h&gt; 中定义,但是 7.18.1.4 表示这两种类型不是强制性的,实现不需要提供它们。

【讨论】:

    【解决方案2】:

    你应该使用类似的东西

    int *pointer;
    intptr_t address=(intptr_t) pointer;
    

    这主要是对@Andrew 帖子的更正

    所以你的函数应该变成

    (哎呀忘了这是作业。我会在一段时间内回滚这个问题。不能直接给你答案:))

    【讨论】:

    • 按照描述更新了我的代码,仍然得到以下输出:addr is 58, taddr is 88, npos is 0 and ntag is 11 当我期望 npos 为 2 而 ntag 为 7.
    • @Air 如果你去easycalculation.com/hex-converter.php 并输入58 它将是88。这些值实际上是相同的,它们只是显示在不同的基础上。
    • 我很确定这是将指针类型转换为整数类型的最标准方法。 +1。
    【解决方案3】:
    int *pointer;
    uint32_t address = (uint32_t) pointer;
    

    当然,您无法保证 int* 适合 uint32_t,因此您需要为您的平台选择正确的类型。

    【讨论】:

    • 如何才能为平台选择合适的类型?我得到一个“`uint32_t' undeclared (first use in this function)”,我认为这意味着它不是正确的类型。
    • @Airjoe,确保您包括&lt;stdint.h&gt;
    【解决方案4】:

    十进制 88 是 0x58(十六进制 58)。当您将 %p 说明符与 printf 一起使用时,会打印出十六进制表示。所以 addr 和 taddr 都是十进制的 88,你的计算是正确的。

    【讨论】:

    • 对,Earlz 上面已经解释过了。所以58不是我想的那样,我的计算仍然是错误的。 (我以为 58 是内存中的实际地址,我想知道为什么它是这么小的数字......)。我需要拆分实际的内存地址,我想我现在根本找不到。
    • %p 格式说明符的规范说:“参数应为指向 void 的指针。指针的值以实现定义的方式转换为打印字符序列。 "它不必以十六进制打印,它可以以八进制或十进制打印,但十六进制可能是最常见的表示。
    • 这里的东西没有加起来。参数addr从何而来?你将什么传递给函数?我怀疑你这样做: int * value = 88;负载(值);相反,您应该执行以下操作: int value = 58;负载(&值);这会将变量值的地址传递给您的函数。
    【解决方案5】:

    这里还没有提到一件重要的事情。当您使用 %p 说明符打印指针时,您应该转换参数:

    printf("addr is %p\n", (void *)addr);
    

    %p 需要一个指向 void 的指针,并且 printf 的说明符/参数不匹配是未定义的行为。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2020-11-08
      • 2017-11-08
      • 2010-12-08
      • 1970-01-01
      • 2012-10-15
      • 1970-01-01
      • 2021-08-28
      相关资源
      最近更新 更多