Domanda

It's been a while since I've written C so this bug makes me feel like I'm losing my mind. I'm writing a program to model a simple cache. Don't worry about the details.

The problem is when I initialize the cache. In the line in SA_cacheInit:

cur_lru = cache->sets + i;//[i];

Using brackets fails and upon inspection in GDB it ends up giving a null pointer even for i = 0. However it works if I just use normal pointer arithmetic. What am I doing wrong?


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; } }

È stato utile?

Soluzione

It seems to me that SA_cache::sets should have type LRU* rather than LRU**. As Jamey pointed out, what you have posted here won't compile cleanly otherwise. The rest of this answer assumes that type is LRU*.

When you write:

cur_lru = cache->sets[i];

cur_lru gets the value at the ith element of cache->sets, which in your case was zero (likely since your process has only just seen this memory for the first time).

If you want to use array subscripting, you need to use the address-of operator (&):

cur_lru = &cache->sets[i];

cur_lru then gets the address of the ith element of cache->sets. This is functionally identical to the pointer arithmetic you posted.

Altri suggerimenti

Since the type of cache->sets is LRU **, the type of cache->sets + i is also LRU **. When you assign the result to LRU *cur_lru, I'd have expected you to get a compiler warning. (Are you building without warnings enabled?)

This assignment from incompatible pointer types means that you're writing into pointers in the sets array as if they were fields of the LRU structure.


edit: On more careful reading, I see you understand that subscripting should be right, and you're reporting that the code only works if you introduce this type error. I stand by the above, and in fact GCC reports "warning: assignment from incompatible pointer type", even without -Wall.

The only other issue I can find in this code is that when you malloc the sets array, you size each element as sizeof(LRU), not sizeof(LRU *). However, whatever platform you're on almost certainly makes the LRU struct bigger than a pointer to LRU, so that shouldn't explain the symptom you're seeing.

Note that if you compile with optimization (gcc -O2 or similar), then the information that gdb reports may be misleading. It's possible that when you introduce the type error, you're preventing gcc from optimizing the initializations, and might be the only reason gdb reports what you expect then.

I strongly encourage you to compile with gcc -Wall and fix all the warnings. Then, if that hasn't fixed the problem, run your program under Valgrind to catch a variety of memory errors.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top