2

自从我写 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; } }

4

2 回答 2

2

在我看来,SA_cache::sets应该有 typeLRU*而不是LRU**. 正如 Jamey 指出的那样,否则您在此处发布的内容将无法完全编译。这个答案的其余部分假设类型是LRU*.

当你写:

cur_lru = cache->sets[i];

cur_lru获取 的第th 元素的,在您的情况下为零(可能是因为您的进程只是第一次看到此内存)。icache->sets

如果要使用数组下标,则需要使用地址运算符 ( &):

cur_lru = &cache->sets[i];

cur_lru然后获取cache->sets的第 th 个元素的地址。i这在功能上与您发布的指针算法相同。

于 2012-11-11T06:50:48.447 回答
1

既然类型cache->setsLRU **,那么类型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下运行您的程序以捕获各种内存错误。

于 2012-11-10T01:15:16.833 回答