检查两个指针​​是否在同一页面上

时间:2015-08-29 14:55:00

标签: c pointers

我看到了这个面试问题,想知道我的功能是否正在做它应该做的事情,或者是否有更好的方法来做到这一点。

这里是问题的确切引用:

  

操作系统通常在页面中分配内存,使页面的基地址为0,4K,8K等。给定两个地址(指针),编写一个函数来查找两个指针是否在同一页面上。这是函数原型:int AreOnSamePage(void * a,void * b);

这是我的实施。如果它介于4k和8k之间,我会返回4。如果它在0到4k之间,则返回1,如果它超过8k,则返回-1。我收到了正确的地址吗?面试问题措辞模糊。使用长按是否正确,因为地址可能很大?

    int AreOnSamePage(void* a, void* b){
       long difference = abs(&a - &b);
       printf("%ld %ld\n",(long)&a,(long)&b);
       if(difference > 8000)
          return -1;
       if(difference >= 4000)
          return 4;
       return 1;
    }

5 个答案:

答案 0 :(得分:3)

ptrdiff_t difference = (ptrdiff_t) abs((char *)a - (char *) b)(uintptr_t)a / 4096 == ( uintptr_t ) b / 4096是指针,因此它们之间的距离为:

int AreOnSamePage(void* a, void* b) { const size_t page_size = 4096; if ( (uintptr_t) a / page_size == (uintptr_t) b / page_size) return 1; else return 0; }

但你不需要它。 两个指针在同一页面上,如果

verified=false

否则他们在不同的页面上。 所以:

verified

答案 1 :(得分:0)

您的代码存在许多问题。

  1. 您正在比较函数参数的地址(它们是并排的,在堆栈上),而不是指针
  2. 您无缘无故地将difference与8000
  3. 进行比较
  4. 4K!= 4000
  5. 想象一个地址是3K,另一个是5K,根据你的代码,它们在同一页面上。
  6. 错误选择返回值

答案 2 :(得分:0)

名称AreOnSamePage()表示该函数返回01;我发现它返回-14或其他值时很奇怪。

如果一个页面是4KB,那么这意味着你需要12位来索引页面内的每个字节(因为2 ^ 12 = 4096),所以只要两个指针值的N-12个最高位比较相等,那么你知道它们在同一页面上(其中N是指针的大小)。

所以你可以这样做:

#include <stdint.h>

static const uintptr_t PAGE_SIZE = 4096;
static const uintptr_t PAGE_MASK = ~(PAGE_SIZE-1);

int AreOnSamePage(void *a, void *b) {
    return (((uintptr_t) a) & PAGE_MASK) == (((uintptr_t) b) & PAGE_MASK);
}

PAGE_MASK是一个位掩码,将所有N-12个最高有效位设置为1,将12个最低有效位设置为0.通过按地址AND执行,我们有效地清除了最不重要的12位(页面的偏移量),因此我们只能比较其他重要位。

请注意uintptr_t保证宽度足以存储指针值,与long不同。

答案 3 :(得分:0)

你试图解决面试的问题是错误的。

您应该比较ab。不是&a&b

但即便如此,它仍然是错的。 考虑指针a指向第0页的最后位置,指针b指向第1页的第一个位置。第1页是第0页后面的一个。 他们的区别是1.但是他们在不同的页面。

为了正确实现它,您应该考虑页面长度为4Kib。 4Kib = 2 ^ 12 = 4096.因此,如果它们在同一页面中,那么对于最后12个指针保存的一对指针的所有位将是相等的。

#include<stdint.h>
int AreOnSamePage(void* a, void* b){
  return ((intptr_t)a & ~(intptr_t)0xFFF) == 
         ((intptr_t)b & ~(intptr_t)0xFFF);
}

更简洁但同等的实施:

int AreOnSamePage(void* a, void* b){
  return ((intptr_t)a)>>12 == ((intptr_t)b)>>12;
}

答案 4 :(得分:0)

如前所述,您应该使用uintptr_t来处理指针。但是,当您测试距离而不是页面时,您的代码是错误的。此外,你忘了计算机使用两个幂。 8000是没有的;那将是8192。类似于4000

测试的最快方法是:

#include <stdbool.h>
#include <stdint.h>

// this should better be found in a system header:
#define PAGESIZE 4096U

bool samePage(void *a, void *b)
{
    return ((uintptr_t)a ^ (uintptr_t)b) < PAGESIZE;
}

或:

    return !(((uintptr_t)a ^ (uintptr_t)b) / PAGESIZE);

请注意,除法的结果将转换为bool。如果将其用作内联,则仅测试零/非零。

XOR将使所有相等的位归零。因此,如果任何更高阶位不同,它们将在XOR之后设置,并使结果> gt = = PAGESIZE。这样可以节省一个分区或屏蔽。

当然,这需要PAGESIZE为2的幂。