【问题标题】:Using comparison operators with pointers to check if it is within an address range?使用带有指针的比较运算符来检查它是否在地址范围内?
【发布时间】:2013-03-29 20:18:36
【问题描述】:

我正在实现一个函数,该函数通过调用deallocate_cache(void *ptr) 来解除分配给它的内存位置。

我手头任务的记忆结构如下:

 22 typedef struct slab {
 23         void *addr;
 24         int bm[((SLAB_SIZE/8)/(8*sizeof(int)))+1]; // bitmap
 25         struct slab *next;
 26 } slab;

 39 typedef struct {
 40         int alloc_unit;
 41         slab S;
 42 } cache;

 45 typedef struct { // structure for the entire memory
 46         cache C[9];
 47         region *R;
 48 } memory;

因此,我有一个memory M,其中包含缓存c[0]c[1]、...、c[8],而这些缓存又包含slabs。当一个slab通过分配填满时,我通过slab *next字段分配另一个作为链表元素。

为了让我的deallocate_cache(void *ptr) 正常工作,我必须首先找出ptr 是否在缓存范围内,如果是,在哪个缓存范围内。这是我到目前为止所拥有的:

 1.    // Check if ptr is in the range of (slab_addr, slab_size) for each slab in each cache
 2. int ci = 0, counter, coefficient, done, freeable;
 3. slab *look_ahead;
 4. for(; ci < 9; ci++){
 5.         void *max_addr = &M.C[ci].S + SLAB_SIZE; // The upper bound of the address range of the first slab
 6.         counter = 1;
 7.         look_ahead = &M.C[ci].S;
 8.         while(look_ahead->next != NULL){
 9.             if( ptr > look_ahead->addr && ptr > max_addr){ // Check ptr is greater than S.addr. If yes, it's a good bet it's in this cache.
10.                 look_ahead = look_ahead->next;
11.                 max_addr += SLAB_SIZE; // Now the upper bound of the address range of the following slab
12.                 counter++; // slab counter, 1-based counting
13.             }
14.             else {
15.                     done = 1;
16.                     break;
17.             }
18.         }
19.         if(done == 1) break;
20.
21. }

不幸的是,很明显,这并没有按预期工作。有什么方法可以使用这样的指针来比较地址,或者检查指针是否在给定的地址范围内?还是我必须简单地比较我知道分配给的最大范围内的每个地址?非常感谢任何帮助。

【问题讨论】:

  • 我什么也不懂。如果你的slab是一个链表,为什么你需要9个不同的缓存?您是否要尽量减少每个平板中的元素数量?如果是这样,为什么 9 缓存?我不希望“max_addr += SLAB_SIZE”正常工作。链表不必在内存中继续(这就是你给它一个指针的原因)。按照你所做的,你可能想做:“max_addr = look_ahead->next + SLAB_SIZE”。这对我来说仍然很奇怪,但至少它遵循你之前所做的事情
  • 我很抱歉,也许我可以更清楚。缓存服务于不同大小的slabs:c[0] 只保存包含 8 字节分配的slab(每个slab 最多8192,8192 等于SLAB_SIZE / M.C[0].alloc_unit),c[1] 保存包含16-字节分配等等。我会考虑你的建议,谢谢。

标签: c pointers void-pointers memory-management


【解决方案1】:

首先,您不能在指向void 的指针中添加或减去任何内容。

指针算法只为指向已知大小事物的指针定义。 voidcharintchar*struct slab 不同,它没有已知的大小。这是因为对指针进行加减运算会使指针​​中的地址按指针所指大小的倍数增加。

所以,如果你有char* p;,那么p = p + 1; 会将sizeof(char)(即1)添加到指针中的地址,但如果你有long* p;,那么p = p + 1; 会添加sizeof(long)(通常是2、4 或 8) 到指针中的地址。

无论多么奇怪,同样的限制适用于将指针与&gt;&lt;&gt;=&lt;= 进行比较。比较的指针必须指向相同的类型,不能是void

我认为您需要使用指向 char 的指针而不是指向 void 的指针,或者将后者转换为前者以进行指针运算。

另一个需要注意的重要事情是,如果这些指针不指向同一个数组或同一个对象(这可以像结构一样聚合)。 C 标准规定这相当于未定义的行为。

因此,如果您分别分配两个对象(作为单独对象的声明或作为对malloc() 或类似的单独调用),那么您不能合法地将指向这两个对象的指针与&gt;&lt;&gt;=, &lt;=.

不过,==!= 可以。

这种比较限制的一个常见解决方法是将指针转换为uintptr_t,这是一种保证能够保存指针的无符号整数类型,并对该整数类型执行常规算术运算,然后在需要时进行转换(强制转换)它回指针类型。

当然,这只有在你的编译器有意义地定义了指向整数的指针和整数到指针的转换并保证从指向它们的指针转换获得的整数值是内存地址时才有效。

使用此信息更正您的代码。

【讨论】:

  • 对于迟到的接受深表歉意,但非常感谢您提供的信息丰富的回答!我最终选择了 char 来解决这个问题。
猜你喜欢
  • 1970-01-01
  • 2013-08-22
  • 1970-01-01
  • 1970-01-01
  • 2021-12-10
  • 2018-11-21
  • 2017-05-28
  • 1970-01-01
  • 2017-05-21
相关资源
最近更新 更多