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, чтобы перехватить множество ошибок памяти.

Другие вопросы по тегам