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

4
  • 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: [] Commented Apr 18, 2016 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. Commented Apr 18, 2016 at 17:32
  • @Olaf. Thank you for suggestions. Please provide your solution if possible. Commented Apr 18, 2016 at 20:09
  • @bruceg. Thank you for suggestions. Please provide your solution if possible. Commented Apr 18, 2016 at 20:09

2 Answers 2

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.

Sign up to request clarification or add additional context in comments.

4 Comments

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

1 Comment

Thank you for your effort. Please notice that allocations is a static variable.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.