c фиксированная реализация пула памяти - PullRequest
1 голос
/ 26 марта 2019

Я пытаюсь реализовать фиксированный пул памяти (свободный список первой подгонки), моя структура:

struct mempool {
    void* data;
    int offset;
};

data разделена на 8-байтовые блоки, 4 байта, указывающие на следующее смещение, и 4байтовые данные.offset указывает на первый свободный блок.Я пытаюсь понять, почему доступ к первому блоку осуществляется с помощью:

int* address = (int*)((int)&pool->data + pool->offset);

особенно части (int)&pool->data.Разве пул-> данные уже не указатель?зачем мне его адрес выполнять арифметику и сдвигать на смещение?

Ответы [ 3 ]

2 голосов
/ 26 марта 2019

Я пытаюсь понять, почему доступ к первому блоку осуществляется с помощью:

int* address = (int*)((int)&pool->data + pool->offset);

особенно часть (int)&pool->data. Не является ли pool->data уже указатель

Да, pool->data - указатель. И можно получить адрес указателя, так что в этом нет ничего плохого. Результат в этом случае имеет тип void **.

Более того, учитывая, что data является первым членом struct mempool, &pool будет указывать на тот же адрес. Хотя последний имеет другой тип (struct mempool *), вероятно, это связано с тем, что код выполняет преобразование в тип int.

зачем мне нужен его адрес для выполнения арифметики и перехода к смещение?

В результате вычисляется адрес относительно местоположения самого указателя data, а не относительно его target . Кроме того, приведение к типу int предполагает, что смещение измеряется в байтах. Однако этот аспект немного небезопасен, поскольку не гарантируется, что тип int достаточно велик для поддержки преобразования туда и обратно из указателя в int в указатель.

Все это, похоже, согласуется с вашей характеристикой пула, имеющего метаданные рядом с данными, но остается неясным, для чего служат указатели data.

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

int* address = (int*)((char *)&pool + pool->offset);

Это позволяет избежать вопроса о целочисленном типе, который может представлять указатели (хотя есть один в форме intptr_t). Приведение к char * учитывает тот факт, что арифметика указателя выполняется в единицах, равных размеру указываемого типа, а смещение представляется в однобайтовых единицах.

1 голос
/ 26 марта 2019

pool->data + pool->offset было бы невозможно, потому что вы не можете сделать арифметику указателей на void указателях - это недопустимо C. Арифметика указателей также предполагает, что базовым типом всего этого является массив.

&pool->data дает адрес самого указателя, который является адресом структуры.Тип void**.Вы также не можете сделать арифметику с этим.

Поэтому наивное, плохое решение здесь - привести указатель к int, а затем сделать простое сложение.Это тоже не работает, потому что int не гарантирует возможность удерживать содержимое указателя.uintptr_t должен был быть использован вместо int.

И, наконец, доступ к этому фрагменту памяти через int* с последующим снятием ссылки на него возможен только в том случае, если то, что там хранится, уже рассматривается как тип * 1016.* компилятором.Если нет, то это вызывает неопределенное поведение, Что такое строгое правило псевдонимов? .

Резюме: это довольно сомнительный код, и есть много лучших способов его реализовать.

1 голос
/ 26 марта 2019

Ваш код не выглядит правильным.Вы добавляете pool->offset к адресу поля pool->data, а не к адресу, хранящемуся в поле pool->data.Я бы посоветовал исправить это так:

int* address = (int *)pool->data + pool->offset;

, если ваше смещение в 4-байтовых чанках, или вот так:

int* address = (int *)((char *)pool->data + pool->offset);

, если ваше смещение в байтах.

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