0

Consider the macro below. How can I unroll the for loops using macros and export lots of macros cleanly into a readable header?

macro.h

#define ARR(n) \
typedef int arr##n[n]; \
void arr##n##_add(arr##n res, arr##n x, arr##n y){ \
    int i = 0; \
    for (; i < n; i++) { \
        res[i] = x[i] + y[i]; \
    } \
}

ARR(3)
ARR(4)

Running this through the pre-processor with gcc -E -P macro.h > out.h we get:

out.h

typedef int arr3[3]; 

void arr3_add(arr3 res, arr3 x, arr3 y){ 
    int i = 0; 
    for (; i < 3; i++) { 
        res[i] = x[i] + y[i]; 
    } 
}

typedef int arr4[4]; 

void arr4_add(arr4 res, arr4 x, arr4 y){ 
    int i = 0; 
    for (; i < 4; i++) { 
        res[i] = x[i] + y[i]; 
    } 
}

Using token pasting like above we avoid having to repeat definitions. Now there are two things I would like to know:

  1. How can each for(;i; i < n) be replaced (unrolled) with e.g:

    res[0] = x[0] + y[0];
    res[1] = x[1] + y[1];
    ...
    res[n] = x[n] + y[n];
    
  2. What is a clean way of exporting lots of macro hackery into a readable header? Should I create a shell function inside my make file exports the final header to an include directory?

Maybe there are better ways of doing this. Any alternatives welcome.

Brian Tompsett - 汤莱恩
  • 5,753
  • 72
  • 57
  • 129
GoofyBall
  • 401
  • 3
  • 8
  • 25
  • 4
    'Clean way' and 'macro hackery' are pretty much mutually exclusive terms. – Jonathan Leffler Dec 13 '15 at 04:14
  • 1
    What is the problem with functions and readable code? – too honest for this site Dec 13 '15 at 04:14
  • Are you sure this is at all beneficial? Why would you want such specialized functions and types, rather than simply taking the dimension as an argument to the functions? – Jonathan Leffler Dec 13 '15 at 04:18
  • Even if this not the best way as part of my C education knowing this would be helpful. So granted that this may not be "beneficial" or "clean" how do we do it? – GoofyBall Dec 13 '15 at 04:21
  • You should probably look at [Boost::Preprocessor](http://www.boost.org/doc/libs/release/libs/preprocessor/), which can be used with C as well as C++. Not that it is going to make the code readable, but (I believe) it will allow you to unwrap your loops. – Jonathan Leffler Dec 13 '15 at 04:25
  • @JonathanLeffler It would be better to not introduce dependencies unnecessarily unless it would be too much work to do ourselves. – GoofyBall Dec 13 '15 at 04:29

1 Answers1

1

Here is one possible solution that is referred to by this answer using these macro functions:

#define ARR(n, m) \
static inline void vec##n##_add(vec##n res, \
        vec##n const u, vec##n const v) { \
        m }

#define ADD(i, n) res[i] = u[i] + v[i]; 
ARR(3, EVAL(REPEAT(3, ADD, ~)))
ARR(4, EVAL(REPEAT(4, ADD, ~)))

Which does as asked but in a convoluted, hacky, ugly way... In particular, the use of recursive macros for what should be an iterative operation.

Community
  • 1
  • 1
GoofyBall
  • 401
  • 3
  • 8
  • 25