5

I was working on a small macro project that requires me to pass a 2 dimensional array literal to one of my macros like so: myMacro({{0, 1, 2}, {2, 1, 0}}). Without having to pass the size of the array literal to the macro, is there a way to have it expand to the following: int[2][3] = { {0, 1, 2}, {2, 1, 0} } or something equivalent (any initialization that preserves the shape of the array will work)? Thanks in advance for any help

a3f
  • 8,517
  • 1
  • 41
  • 46
NerdicViking
  • 137
  • 9
  • Is it 2-D or arbitrary dimensions? Also, do you have some upper bound for the second index (number of columns)? – Santeri Paavolainen Jan 05 '15 at 17:36
  • It will always be 2d, but it can be any width/length. For example, it could also be called as `myMacro{{1, 2, 3, 4}, {5, 6, 7, 8}})`. There is no upper bound, but the number of columns will always be the same for each row. – NerdicViking Jan 05 '15 at 17:37
  • Try a variadic macro perhaps? – n. m. could be an AI Jan 05 '15 at 17:40
  • @n.m. I am currently using a variadic macro, but I need to be able to bind `__VA_ARGS__` to a variable for later usage. – NerdicViking Jan 05 '15 at 17:41
  • Oh this is C. The only way I know to approach this is by stealing the Boost::Preprocessor library. Boost is a C++ library but the preprocessor part should work for C with minimal or no modification. – n. m. could be an AI Jan 05 '15 at 17:51

2 Answers2

5
#include <boost/preprocessor/tuple/size.hpp>
#include <boost/preprocessor/tuple/elem.hpp>
#include <boost/preprocessor/variadic/to_seq.hpp>
#include <boost/preprocessor/seq/for_each.hpp>

#define VA(...) __VA_ARGS__
#define TRANS(r, data, elem) { VA elem},

#define myMacro(name, arg)\
    int name[BOOST_PP_TUPLE_SIZE(arg)][BOOST_PP_TUPLE_SIZE(BOOST_PP_TUPLE_ELEM(0,arg))] = \
    { BOOST_PP_SEQ_FOR_EACH(TRANS, , BOOST_PP_VARIADIC_TO_SEQ arg)}

int main(){
    myMacro(a, ((1,2,3),(4,5,6)) );//=>int a[2][3] = { { 1,2,3}, { 4,5,6}, };
    return 0;
}
BLUEPIXY
  • 39,699
  • 7
  • 33
  • 70
  • Oh, sorry, I didn't see this answer until now. Does this work in C (pre-99, preferably)? I thought that Boost was C++ only? – NerdicViking Jan 05 '15 at 19:35
  • @NerdicViking part of the preprocessor of boost will work even C. The decision to work with C99 previous C can not be guaranteed, but it was confirmed work with VC2010. – BLUEPIXY Jan 05 '15 at 19:41
  • @BLUEPIXY cool, I didn't know Boost had those kinds of macros. I checked with GCC, and C99 level is required (earlier will fail in preprocessor). – Santeri Paavolainen Jan 06 '15 at 17:19
  • @SanteriPaavolainen yes, variadic macro seems to be from the C99. – BLUEPIXY Jan 06 '15 at 17:27
3

If you have an upper limit for the second dimension then you could use sentinel values such as:

#include <stdio.h>

#define MAXCOLUMNS 20
#define VALUE {{0,1,2,-1},{2,3,4,-1},{0,0,0,0,1,-1},{-1}}

int main()
{
  int v[][MAXCOLUMNS] = VALUE;
  int x, y;

  for (y = 0; v[y][0] != -1; y++)
    for (x = 0; v[y][x] != -1; x++)
      printf("[%d,%d] = %d\n", x, y, v[y][x]);

  return 0;
}

This will print out the values without knowing the exact dimensions beforehand. Is this something you are trying to achieve?

Edit: @BLUEPIXYs solution doesn't require knowing or guessing maximum dimensions, on the other hand this works with older C versions (not a big concern, though).

  • An upper value could work, but only for the first element. The code should be able to guess how many different rows there are (one to correspond to each element of an enum created by another macro, which I can add a `ENUM_SIZE` value to the end of to count the rows, but the length of the individual columns is unknown. – NerdicViking Jan 05 '15 at 17:48
  • The solution I went with is guessing how big it might get. I was trying to do something with: `#define VA_NUM_ARGS(_1, _2, _3, _4, N ...) N` but that only works up to 63 and may also be wrong depending on what number is passed, so I couldn't use that. – NerdicViking Jan 05 '15 at 18:05