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

5
  • Is it 2-D or arbitrary dimensions? Also, do you have some upper bound for the second index (number of columns)? Commented Jan 5, 2015 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. Commented Jan 5, 2015 at 17:37
  • Try a variadic macro perhaps? Commented Jan 5, 2015 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. Commented Jan 5, 2015 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. Commented Jan 5, 2015 at 17:51

2 Answers 2

7
#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;
}
Sign up to request clarification or add additional context in comments.

4 Comments

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 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 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).
@SanteriPaavolainen yes, variadic macro seems to be from the C99.
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).

2 Comments

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

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.