C DMA - Использование скобок с неправильной памятью
Прошло много времени с тех пор, как я написал C, поэтому эта ошибка заставляет меня чувствовать, что я схожу с ума. Я пишу программу для моделирования простого кэша. Не беспокойтесь о деталях.
Проблема в том, когда я инициализирую кеш. В строке в SA_cacheInit:
cur_lru = cache->sets + i;//[i];
Использование скобок дает сбой, и после проверки в GDB он заканчивает тем, что дает нулевой указатель даже для i = 0. Однако это работает, если я просто использую обычную арифметику указателей. Что я делаю неправильно?
typedef struct s_LRUnode {
int tag;
bool valid;
bool dirty;
struct s_LRUnode *next;
struct s_LRUnode *prev;
} LRUnode;
typedef struct s_LRU {
size_t size;
LRUnode *head;
LRUnode *tail;
} LRU;
typedef struct s_SA_cache {
size_t blocksize;
size_t num_blocks;
size_t set_size;
LRU **sets;
} SA_cache;
void cachesim_init(int blocksize, int cachesize, int ways) {
cache = malloc(sizeof(SA_cache));
if ( cache != NULL ) {
assert( powerOfTwo(cachesize) && powerOfTwo(blocksize) );
cache->num_blocks = cachesize / blocksize;
cache->blocksize = blocksize;
cache->set_size = ways;
cache->sets = malloc(sizeof(LRU)*cache->num_blocks); //cache->num_blocks*ways);
if (cache->sets == NULL) {
printf(stderr, "Malloc failed in %s\n", func);
}
SA_cacheInit(cache, cache->num_blocks, ways);
} else {
fprintf(stderr, "Could not allocate memory for cache\n");
exit(-1);
}
}
void SA_cacheInit(SA_cache *cache, size_t num_blocks, size_t size) {
int i;
LRU *cur_lru;
for (i = 0; i < num_blocks; i++) {
cur_lru = cache->sets + i;//[i];
cur_lru->size = size;
cur_lru->head = NULL;
cur_lru->tail = NULL;
}
}
2 ответа
Мне кажется, что SA_cache::sets
должен иметь тип LRU*
скорее, чем LRU**
, Как отметил Джейми, то, что вы разместили здесь, иначе не будет скомпилировано. Остальная часть этого ответа предполагает, что тип LRU*
,
Когда вы пишете:
cur_lru = cache->sets[i];
cur_lru
получает значение на i
й элемент cache->sets
, который в вашем случае был равен нулю (вероятно, так как ваш процесс только что видел эту память впервые).
Если вы хотите использовать подписку на массив, вам нужно использовать оператор address-of (&
):
cur_lru = &cache->sets[i];
cur_lru
затем получает адрес i
ый элемент кеша -> наборы. Это функционально идентично арифметике указателей, которую вы разместили.
Так как тип cache->sets
является LRU **
, тип cache->sets + i
это также LRU **
, Когда вы назначаете результат LRU *cur_lru
Я бы ожидал, что вы получите предупреждение компилятора. (Вы строите без включенных предупреждений?)
Это назначение из несовместимых типов указателей означает, что вы пишете в указатели в sets
массив, как если бы они были полями LRU
состав.
редактировать: при более внимательном прочтении, я вижу, вы понимаете, что подписка должна быть правильной, и вы сообщаете, что код работает, только если вы вводите эту ошибку типа. Я поддерживаю вышеизложенное, и на самом деле GCC сообщает "Предупреждение: назначение из несовместимого типа указателя", даже без -Wall
,
Единственная другая проблема, которую я могу найти в этом коде, заключается в том, что когда вы malloc
sets
массив, вы определяете размер каждого элемента как sizeof(LRU)
не sizeof(LRU *)
, Тем не менее, на какой бы платформе вы ни находились, LRU
структура больше, чем указатель на LRU
, так что это не должно объяснять симптом, который вы видите.
Обратите внимание, что если вы компилируете с оптимизацией (gcc -O2
или аналогичный), то информация, которая gdb
отчеты могут вводить в заблуждение. Возможно, что когда вы вводите ошибку типа, вы предотвращаете gcc
от оптимизации инициализации, и может быть единственной причиной gdb
сообщает, что вы ожидаете тогда.
Я настоятельно рекомендую вам собрать с gcc -Wall
и исправить все предупреждения. Затем, если это не устранило проблему, запустите вашу программу под Valgrind, чтобы перехватить множество ошибок памяти.