title: How to modify or create a struct depending on argument?
body: <p>I must further develop a simulator using C, capable of simulating different cache types (direct, n-way associative, fully associative). Right now my code works in the sense that it can simulate a direct-mapped cache, however it cannot simulate any other type.</p>
  <p><strong>My Code</strong>
  My C file:</p>
  <pre><code>   /*
   * CS3375 Computer Architecture
   * Course Project
   * Cache Simulator Design and Development
   * FALL 2017
   * By Yong Chen
   */
  
  #include &lt;stdio.h&gt;
  #include &lt;stdint.h&gt;
  #include &lt;string.h&gt;
  #include &lt;math.h&gt;
  #include &quot;cachesim.h&quot;
  int main(int argc, char *argv[])
  {
      char type;
      if (argc != 3) {
          printf(&quot;Usage: %s &lt;direct&gt; &lt;trace file name&gt;\n&quot;, argv[0]);
          return 1;
      }
  
  #ifdef DBG
      printf(&quot;BLOCK SIZE = %d Bytes\n&quot;, BLOCK_SIZE);
      printf(&quot;%d-WAY\n&quot;, WAY_SIZE);
      printf(&quot;CACHE SIZE = %d Bytes\n&quot;, CACHE_SIZE);
      printf(&quot;NUMBER OF BLOCKS = %d\n&quot;, NUM_BLOCKS);
      printf(&quot;NUMBER OF SETS = %d\n&quot;, NUM_SETS);
      printf(&quot;\n&quot;);
  #endif
      struct direct_mapped_cache d_cache;
      char* trace_file_name = argv[2];
      char mem_request[20];
      uint64_t address;
      FILE *fp;
  
  
      /* Initialization */
      for (int i=0; i&lt;NUM_BLOCKS; i++) {
          d_cache.valid_field[i] = 0;
          d_cache.dirty_field[i] = 0;
          d_cache.tag_field[i] = 0;
      }
  
      d_cache.hits = 0;
      d_cache.misses = 0;
  
      /* Opening the memory trace file */
      fp = fopen(trace_file_name, &quot;r&quot;);
  
      /*Checks if argument specified direct-mapped cache*/
      if (strncmp(argv[1], &quot;direct&quot;, 6)==0) { /* Simulating direct-mapped cache */
          /* Read the memory request address and access the cache */
          while (fgets(mem_request, 20, fp)!= NULL) {
              address = convert_address(mem_request);
              direct_mapped_cache_access(&amp;d_cache, address);
          }
          /*Calculate Hit and Miss Rate*/
          double hit_rate = ((1.0 * d_cache.hits)/(d_cache.hits + d_cache.misses));
          double miss_rate = ((1.0 * d_cache.misses)/(d_cache.hits + d_cache.misses));
          /*Print out the results*/
          printf(&quot;\n==================================\n&quot;);
          printf(&quot;Cache type:    Direct-Mapped Cache\n&quot;);
          printf(&quot;==================================\n&quot;);
          printf(&quot;Cache Hits:    %d\n&quot;, d_cache.hits);
          printf(&quot;Cache Misses:  %d\n&quot;, d_cache.misses);
          printf(&quot;Cache Hit Rate: %f\n&quot;, hit_rate);
          printf(&quot;Cache Miss Rate: %f\n&quot;, miss_rate);
          printf(&quot;\n&quot;);
      }
  
      fclose(fp);
  
      return 0;
  }
  
  uint64_t convert_address(char memory_addr[])
  /* Converts the physical 32-bit address in the trace file to the &quot;binary&quot; \\
   * (a uint64 that can have bitwise operations on it) */
  {
      uint64_t binary = 0;
      int i = 0;
  
      while (memory_addr[i] != '\n') {
          if (memory_addr[i] &lt;= '9' &amp;&amp; memory_addr[i] &gt;= '0') {
              binary = (binary*16) + (memory_addr[i] - '0');
          } else {
              if(memory_addr[i] == 'a' || memory_addr[i] == 'A') {
                  binary = (binary*16) + 10;
              }
              if(memory_addr[i] == 'b' || memory_addr[i] == 'B') {
                  binary = (binary*16) + 11;
              }
              if(memory_addr[i] == 'c' || memory_addr[i] == 'C') {
                  binary = (binary*16) + 12;
              }
              if(memory_addr[i] == 'd' || memory_addr[i] == 'D') {
                  binary = (binary*16) + 13;
              }
              if(memory_addr[i] == 'e' || memory_addr[i] == 'E') {
                  binary = (binary*16) + 14;
              }
              if(memory_addr[i] == 'f' || memory_addr[i] == 'F') {
                  binary = (binary*16) + 15;
              }
          }
          i++;
      }
  
  #ifdef DBG
      printf(&quot;%s converted to %llu\n&quot;, memory_addr, binary);
  #endif
      return binary;
  }
  
  void direct_mapped_cache_access(struct direct_mapped_cache *cache, uint64_t address)
  {
      uint64_t block_addr = address &gt;&gt; (unsigned)log2(BLOCK_SIZE);
      uint64_t index = block_addr % NUM_BLOCKS;
      uint64_t tag = block_addr &gt;&gt; (unsigned)log2(NUM_BLOCKS);
  
  #ifdef DBG
      printf(&quot;Memory address: %llu, Block address: %llu, Index: %llu, Tag: %llu &quot;, address, block_addr, index, tag);
  #endif
  
      if (cache-&gt;valid_field[index] &amp;&amp; cache-&gt;tag_field[index] == tag) { /* Cache hit */
          cache-&gt;hits += 1;
  #ifdef DBG
          printf(&quot;Hit!\n&quot;);
  #endif
      } else {
          /* Cache miss */
          cache-&gt;misses += 1;
  #ifdef DBG
          printf(&quot;Miss!\n&quot;);
  #endif
          if (cache-&gt;valid_field[index] &amp;&amp; cache-&gt;dirty_field[index]) {
              /* Write the cache block back to memory */
          }
          cache-&gt;tag_field[index] = tag;
          cache-&gt;valid_field[index] = 1;
          cache-&gt;dirty_field[index] = 0;
      }
  }
  </code></pre>
  <p>My .h file:</p>
  <pre><code>    /*
   * CS3375 Computer Architecture
   * Course Project
   * Cache Simulator Design and Development
   * FALL 2017
   * By Yong Chen
   */
  
  #include &lt;stdio.h&gt;
  /* Cache block size (or cache line size) in bytes*/
  #define BLOCK_SIZE  64          /*(must be power of 2). 4 Bytes = 1 Word NOTE: MUST CHANGE DEPENDING ON TYPE*/
  #define WAY_SIZE    1              /* Associativity; 1-way = direct-mapped MUST CHANGE DEPENDING ON TYPE*/
  #define CACHE_SIZE  32768       /* Cache capacity in bytes (must be power of 2) THIS WILL STAY FIXED*/
  
  #define NUM_BLOCKS  (CACHE_SIZE / BLOCK_SIZE)
  #define NUM_SETS  (BLOCK_SIZE/WAY_SIZE)
  /*For fully associative, num sets is equal to num blocks because way size is equal to num blocks. */
  
  /*MAY TRY LEAVING THESE VARIABLES UNDEFINED, AND THEY WILL BE SET DEPENDING ON USER INPUT.*/
  
  #define DBG /*Prints debugging information*/
  
  /*The data structure of direct-mapped cache*/
  struct direct_mapped_cache {
      unsigned valid_field[NUM_BLOCKS];   /* Valid field */
      unsigned dirty_field[NUM_BLOCKS];   /* Dirty field; since we don't distinguish writes and \\
                                             reads in this project yet, this field doesn't really matter */
      uint64_t tag_field[NUM_BLOCKS];     /* Tag field */
      char data_field[NUM_BLOCKS][BLOCK_SIZE];  /* Data field; since we don't really fetch data, \\
                                                   this field doesn't really matter */
      int hits;                          /* Hit count */
      int misses;                        /* Miss count */
  };
  
  
  /*Read the memory traces and convert it to binary*/
  uint64_t convert_address(char memory[]);
  
  /*Simulate the direct-mapped cache*/
  void direct_mapped_cache_access(struct direct_mapped_cache *cache, uint64_t address);
  
  </code></pre>
  <p><strong>What I've Tried</strong>
  Admittedly, I am a beginner when it comes to the C language, so my solution may be simpler than I think, but I've been unable to find any answers thus far. I've considered changing where the cache variables were defined using &quot;#define&quot; depending on the argument, but I have learned that &quot;#define&quot; is run by pre-processing, so this won't work.</p>
  <p>I've also tried creating multiple struct classes for each type of cache that needs to be simulated, but since struct variables in C cannot be initialized within the class, I can't get this to work either.</p>
  <p>To my understanding, structs in C cannot have constructors either, as I've looked into this as well.</p>
  <p>Any help or step in the right direction will be greatly appreciated.</p>