2013-04-07 1 views
4

Я реализую функцию, которая освобождает место памяти, которое было ему предоставлено, путем вызова 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. } 

К сожалению, и, скорее, это не работает должным образом. Можно ли использовать указатели, подобные этому, для сравнения адресов или проверить, находится ли указатель в заданном диапазоне адресов? Или мне нужно просто сравнить каждый отдельный адрес в максимальном диапазоне, который, как я знаю, я выделил? Буду признателен за любую оказанную помощь.

+0

Я ничего не понимаю. Если вы используете слэб - это связанный список, зачем вам нужен 9 разных кешей? Вы пытаетесь минимизировать количество элементов в каждой плите? Если да, то почему 9 кеш? Я не ожидаю, что «max_addr + = SLAB_SIZE» будет работать правильно. Связанный список не должен быть продолжен в памяти (поэтому вы даете ему указатель). Следуя тому, что вы делаете, вы, вероятно, захотите сделать: «max_addr = look_ahead-> next + SLAB_SIZE». Мне все это кажется странным, но, по крайней мере, это то, что вы делали ранее. –

+0

Мои извинения, возможно, я мог бы быть более ясным. Кэши служат для различных «слябов»: c [0] содержит только плиты, которые содержат 8-байтовые распределения (до 8192 на 'slab', 8192 равны' SLAB_SIZE/MC [0] .alloc_unit'), c [ 1] содержит плиты, содержащие 16-байтовые распределения и т. Д. Я рассмотрю ваше предложение, спасибо. – user991710

+0

Немного связано: http://stackoverflow.com/questions/4023320/how-to-implement-memmove-in-standard-c-without-an-intermediate-copy – ninjalj

ответ

3

Во-первых, вы ничего не можете добавить или вычесть из указателя на void.

Арифметика указателя определяется только для указателей, указывающих на вещи известных размеров. void, в отличие от char или int или char* или struct slab, не имеет известного размера. И это потому, что добавление или вычитание из указателя продвигает адрес в указателе на кратное размеру указателя.

Итак, если у вас есть char* p; того p = p + 1; добавляет sizeof(char) (который 1) по адресу в указателе, но если у вас есть long* p; того p = p + 1; добавляет sizeof(long) (который обычно составляет 2, 4 или 8) по адресу в указатель.

Однако нечетное, то же ограничение применяется для сравнения указателей с >, <, >=, <=. Сравнимые указатели должны указывать на один и тот же тип, который не может быть void.

Я думаю, что вам нужно использовать указатели на char вместо указателей на void или перевести последний в первый, чтобы выполнить арифметику указателя.

Другая важная вещь, чтобы отметить, что по закону вы не можете сравнить указатели с >, <, >=, <= если эти указатели не указывают на тот же массив или в тот же объект (который может быть как заполнитель структуры) , В стандарте C указано, что это означает неопределенное поведение.

Итак, если вы выделить два объекта отдельно (в виде деклараций отдельных объектов или в виде отдельных вызовов на malloc() или аналогичный), то вы не можете законно сравнивать указатели на этих двух объектов с >, <, >=, <=.

== и != можно сделать, однако.

Общепринятое обходное ограничение для этого ограничения сравнения заключается в том, чтобы указать указатели на uintptr_t, целочисленный тип без знака, который гарантированно сможет удерживать указатель и выполнять регулярные арифметические операции над этим целым типом, а затем, при необходимости, преобразовать (лить) обратно к типу указателя.

Это, конечно же, будет работать только в том случае, если ваш компилятор определяет указатель на целое и целое число для преобразования указателей значимым образом и гарантирует, что целые значения, полученные от преобразования указателей на них, являются адресом памяти.

Используйте эту информацию, чтобы исправить ваш код.

+0

Приносим извинения за поздний прием, но большое спасибо за ваш информативный ответ! Я закончил тем, что решил, чтобы решить проблему. – user991710

 Смежные вопросы

  • Нет связанных вопросов^_^