2

There is the following code (C99):

#define MAX_ALLOCATIONS 2

#if !defined(ALLOCATIONS)
  #define ALLOCATIONS {{1, 0, 0, 64},{1, 0, 0, 32}}
#endif

struct allocation
{
  int thread_count_;

  int node_run_;

  int node_alloc_;

  int size_alloc_;
};

static struct allocation allocations[MAX_ALLOCATIONS] = ALLOCATIONS;

When compiling this code it is possible to pass something like this: -D'ALLOCATIONS={{1, 0, 0, 8},{1, 0, 0, 16},{1, 0, 0, 4}}'.

Is it possible to get a macro that would compute the number of allocations? For example, it should compute 3 when it gets {{1, 0, 0, 8},{1, 0, 0, 16},{1, 0, 0, 4}}. This would allow to get rid of MAX_ALLOCATIONS in the code above. Yes, the easy way would be to pass something like -DMAX_ALLOCATIONS=3 alone with -D'ALLOCATIONS={{1, 0, 0, 8},{1, 0, 0, 16},{1, 0, 0, 4}}' but it is error-prone for a user.

Thank you

Dimon
  • 436
  • 5
  • 15
  • What is the benefit for this obfuscation over having the initialiser with the `struct` instead of a macro without reference to the struct type or fields? And there is no variadic macro shown. Let apart that it is not what you seem to want. C provides better and easier features for what you want. Shown in every good book. Hint: `[]` – too honest for this site Apr 18 '16 at 17:21
  • It seems like the definition of ALLOCATIONS is entirely dependent on the value of MAX_ALLOCATIONS. Surely, you can create the ALLOCATIONS macro that takes the value of MAX_ALLOCATIONS as input. – bruceg Apr 18 '16 at 17:32
  • @Olaf. Thank you for suggestions. Please provide your solution if possible. – Dimon Apr 18 '16 at 20:09
  • @bruceg. Thank you for suggestions. Please provide your solution if possible. – Dimon Apr 18 '16 at 20:09

2 Answers2

3

You do not need to use MAX_ALLOCATIONS when you define the array allocations.

All you need to do is, define ALLOCATIONS as your elements, and the size of the array is determined automatically.

When you need the size of that array in your code, use this macro, it will give the number of elements in the array allocations:

#define MAX_ALLOCATIONS (sizeof(allocations)/sizeof(allocations[0]))

This is a constant value.

2501
  • 25,460
  • 4
  • 47
  • 87
  • Thank you. I tested your approach and it works. All I did is changed to `static struct allocation allocations[] = ALLOCATIONS;` At the beginning I thought that `allocations[0]` may cause a problem if you pass -DALLOCATIONS={}, but apparently it also worked. I created a loop with `printf()` to print all `allocations` and `sizeof(allocations)/sizeof(allocations[0])` works as a loop exit condition even when passing `{}`. – Dimon Apr 18 '16 at 20:31
  • @Dimon Apparently you're using an extension or a C++ compiler. To get correct C code, pass `{{0}}` In that case the array still has one element that is initialized to default values. – 2501 Apr 18 '16 at 20:35
  • Ok thanks. However it works even with `-D'ALLOCATIONS={}'`. My compilation line to test this is: `gcc -Wl,--no-as-needed -lnuma -lpthread -D'ALLOCATIONS={}' program.c -o program`. Then in the program my loop to iterate `allocations` is `for (i = 0; i < sizeof(allocations)/sizeof(allocations[0]); i++)`. The loop doesn't enter in this case – Dimon Apr 18 '16 at 20:50
  • Ok. It looks like I need to know the size of that array at preprocessor level because there is another expansion macro where it is needed. – Dimon Apr 18 '16 at 22:07
0

Is it possible to get a macro that would.

Yes... Perhaps with a macro, but surely programmatically. For example:

(Compiled on Linux> gcc -o test -D'ALLOCATIONS="{{1, 0, 0, 8},{1, 0, 0, 16},{1, 0, 0, 4}}"' *.c):

#include <stdio.h>
#include <string.h>
#include <errno.h>
#include <stdlib.h>   // malloc()

typedef struct allocation_s
   {
   int thread_count_;
   int node_run_;
   int node_alloc_;
   int size_alloc_;
   } allocation_t;

/** **************************************************************************
* Print allocation records.
*/
int PrintRecords(
      allocation_t *I__allocations,
      int           I__elements
      )
   {
   int rCode = 0;
   int index;

   for(index=0; index < I__elements; ++index, ++I__allocations)
      printf("{%d, %d, %d, %d}\n",
         I__allocations->thread_count_,
         I__allocations->node_run_,
         I__allocations->node_alloc_,
         I__allocations->size_alloc_
         );

   return(rCode);
   }

/** **************************************************************************
* Read a record from allocation string.
*/
int ReadRecord(
      char          *I__string,
      char         **_O_next,
      allocation_t  *_O_record
      )
   {
   int   rCode = 0;
   char *cp    = I__string;
   allocation_t record;

   while(*cp && (' ' == *cp || ',' == *cp))
      ++cp;

   if('{' != *cp)
      {
     rCode=EINVAL;
      fprintf(stderr, "[1]Allocations parsing error.\n");
      goto CLEANUP;
      }

   while(*cp && (' ' == *cp || '{' == *cp))
      ++cp;

   record.thread_count_ = strtoul(cp, &cp, 10);
   while(*cp && (' ' == *cp || ',' == *cp))
      ++cp;

   record.node_run_ = strtoul(cp, &cp, 10);
   while(*cp && (' ' == *cp || ',' == *cp))
      ++cp;

   record.node_alloc_ = strtoul(cp, &cp, 10);
   while(*cp && (' ' == *cp || ',' == *cp))
      ++cp;

   record.size_alloc_ = strtoul(cp, &cp, 10);
   cp=strchr(cp, '}');
   if(!cp)
      {
      rCode=EINVAL;
      fprintf(stderr, "[2]Allocations parsing error.\n");
      goto CLEANUP;
      }

   ++cp;

//RESULTS:

   if(_O_record)
      memcpy(_O_record, &record, sizeof(*_O_record));

   if(_O_next)
      *_O_next = (char *)cp;

CLEANUP:

   return(rCode);   
   };   

/** **************************************************************************
* Program start.
*/
int main(
      int   I__argC,
      char *I__argV[]
      )
   {
   int rCode=0;
   char *rawDataString = ALLOCATIONS;
   char *cp = rawDataString;
   int   elements = 0;
   allocation_t *allocations_A = NULL;
   allocation_t *allocationsPtr;
   int   index;

   if('{' != *cp)
      {
      fprintf(stderr, "Allocations parsing error.\n");
      goto CLEANUP;
      }

   /** -----------------------------------------------------------------------
   * Count the elements.
   */
   do {
      rCode=ReadRecord(cp, &cp, NULL);
      ++elements;         
      } while(!rCode && ',' == *cp);  
   if(rCode)
      {
      fprintf(stderr, "ReadRecord() reports: %d\n", rCode);
      goto CLEANUP;
      }

   /** -----------------------------------------------------------------------
   * Allocate the array.
   */
   errno=0;
   allocations_A = malloc(sizeof(*allocations_A) * elements);
   if(!allocations_A)
      {
      rCode=errno;
      fprintf(stderr, "malloc() failed: errno:[%d] %s\n", rCode, strerror(rCode));
      goto CLEANUP;
      }

   /** -----------------------------------------------------------------------
   * Initialize the array.
   */
   cp = rawDataString;
   allocationsPtr = allocations_A;
   for(index=0; index < elements; ++index)
      {
      rCode=ReadRecord(cp, &cp, allocationsPtr++);
       if(rCode)
         {
         fprintf(stderr, "ReadRecord() reports: %d\n", rCode);
         goto CLEANUP;
         }
      }   

   /** -----------------------------------------------------------------------
   * Print the array.
   */
   PrintRecords(allocations_A, elements);

CLEANUP:

   return(rCode);   
   } 

Example output:

{1, 0, 0, 8}
{1, 0, 0, 16}
{1, 0, 0, 4}
Mahonri Moriancumer
  • 5,993
  • 2
  • 18
  • 28