Как я могу переписать первую часть структуры в памяти указателем? - PullRequest
0 голосов
/ 17 января 2010

У меня есть адрес памяти начала ряда структур, но мне нужно исключить некоторые из моего вывода. Я думаю, что пространство памяти будет выглядеть примерно так:

+------------------+------------------+------------------+
|      struct      |     struct       |     struct       |
|  linux_dirent64{ |  linux_dirent64{ |  linux_dirent64{ |
|      first}      |     second}      |     third}       |
+------------------+------------------+------------------+
                    |*p|-------------->| |

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

Я знаю, что было бы более простое решение, если бы я изменил структуру, включив в нее то, что мне нужно, но, к сожалению, это не вариант, поскольку он является частью ядра Linux.

Спасибо за любые ответы.

РЕДАКТИРОВАТЬ: Поскольку все заинтересованы, я фильтрую структуры на основе имени файла. В данный момент я буквально перезаписываю часть d_name буквой O, чтобы она не возвращалась системным вызовом. Однако это вызывает различные проблемы в зависимости от того, какое приложение выдает системный вызов, поэтому мне нужен более тщательный способ избавиться от экземпляра структуры.

С тех пор я придумал следующее, однако ядро ​​убивает его, если тест d_name возвращает true.

while(pos < length){
    printk("d_name = %s\t| pos = %i\t| d_reclen = %i\t| st = %i|\n", dirent->d_name, pos, dirent->d_reclen, st);
    if((st = strcmp(dirent->d_name, "testFile")) == 0){
        printk("Out of context file %s\n", dirent->d_name);
        posOverwrite = pos;
        size = dirent->d_reclen;
        while(posOverwrite < length){
            struct linux_dirent64 *next = (struct linux_dirent64 *)(pos + dirent->d_reclen);
            memcpy(dirent, next, sizeof(next));
            dirent = next;
            next = next + next->d_reclen;
        }
        dirent = (struct linux_dirent64 *) pos;
        continue;
    }
    pos = pos + dirent->d_reclen; //Push our position along according to the size of the dirent
    dirent = (struct linux_dirent64 *) (p+pos); //point our dirent to the next calculated system dirent
}

В конце концов я решил эту проблему, создав новый буфер памяти и скопировав все необходимые мне структуры в новый буфер, исключив все, что я не сделал, основываясь на тесте d_name. После того, как я просмотрел весь список, я запомнил весь новый список. Спасибо за помощь, ребята:)

Ответы [ 4 ]

2 голосов
/ 17 января 2010

Что вы подразумеваете под "может быть, мне нужно пропустить"? Я предполагаю, что у вас есть массив структур, и есть некоторые элементы этого массива, которые вы хотите удалить?

Массивы должны быть смежными. Так что, как правило, есть два способа сделать это - в зависимости от того, как ваш код структурирован, один или другой может быть проще.

  1. Поменяйте местами элемент, который вы хотите удалить, с первым элементом в массиве, затем увеличьте указатель на первый элемент в массиве и уменьшите количество элементов в массиве

  2. Поменяйте местами элемент, который вы хотите удалить, с последним элементом в массиве, затем уменьшите количество элементов в массиве

Конечно, это только для внешности. Не позволяйте этим операциям с указателями испортить ваше управление памятью.

1 голос
/ 17 января 2010

Вот некоторый непроверенный код, смоделированный после remove_if из C ++:

typedef struct linux_dirent64 dirent;

/* example predicate function - modify as needed */
/* returns nonzero if the file should be filtered out */
int has_foo_prefix(const dirent* ent)
{
  return !strncmp(ent->d_name, "foo", 3);
}

/* given a predicate, moves "good" entries to front, returns new end */
typedef int (*predicate)(const dirent*);
dirent* filter(dirent* array, dirent* end, predicate pred)
{
  for (dirent* slow = array, fast = array; fast < end; fast++) {
    if (!pred(*fast)) { /* keep this entry */
      if (fast != slow) { /* need to move this entry forward */
        memcpy(slow, fast, sizeof(dirent));
      }
      slow++;
    }
  }
  return slow;
}

/* example call */
dirent* array = ..., end = ...;
end = filter(array, end, has_foo_prefix);

Идея состоит в том, что ненужные элементы массива шаг за шагом перезаписываются с желаемыми, оставляя только нужные элементы в начале массива, который затем фактически имеет новый (обычно меньший) размер. Это O (n) и делает минимальное распределение.

В моем коде есть одна важная ошибка, которую я пока оставляю без внимания: переменная длина элементов массива. Если более длинный элемент должен заменить более короткий, это проблема. И в любом случае код, который я написал, нуждается в большем количестве указателей, чтобы правильно перемещаться по массиву, но я оставляю его как есть, чтобы быть построенным на нем. Я отмечу, что по мере продвижения по массиву и пропуска некоторых элементов вы будете видеть эту проблему все реже и реже из-за дополнительного пространства, выделяемого «плохими» элементами. Таким образом, время выполнения не может быть хуже, чем в упрощенном варианте, если ввод не является патологическим.

0 голосов
/ 17 января 2010

То, что вы описываете, не имеет смысла.

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

struct linux_dirent {
    unsigned long   d_ino;
    unsigned long   d_off;
    unsigned short  d_reclen;
    char        d_name[1];
};

Вы пропускаете немного d_ino? Какие из них?

0 голосов
/ 17 января 2010

Здесь вы смешиваете вещи - у вас есть массив структур фиксированного размера; Вы не можете действительно превратить это в структуру типа связанного списка на месте. Для того, чтобы делать то, что вы хотите, каждый раз, когда вы найдете, что удалить, вам придется копировать остальную часть списка в предыдущую позицию.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...