0

I have always used C macros for pretty basic things. Are C macros powerful enough to do things like :

  1. Counting:

    COUNT(a,b,c)
    COUNT(e,f)
    

    -->

    3
    2
    
  2. Taking an arbitrary number of parameters (say here up to 5) and replacing missing ones by -1:

     ARRAY(a,b,c)
     ARRAY(e,f)
    

    -->

    const int array[5]={a,b,c,-1,-1};
    const int array[5]={e,f,-1,-1,-1};
    
  3. Replacing what is not a number or mathematical sign with an incrementing counter:

     FORMULA(a*3+5*(b+a))
    

    -->

    array[0]*3+5*(array[1]+array[0])
    
HolyBlackCat
  • 78,603
  • 9
  • 131
  • 207
Lolo
  • 3,935
  • 5
  • 40
  • 50
  • 1
    I can see that you are an experienced user ... but perhaps split this into 3 different questions? – Lover of Structure Aug 09 '23 at 07:12
  • Notice that **C code can be *generated*** by more powerful macroprocessors like [GNU m4](https://www.gnu.org/software/m4/m4.html) or [GPP](https://logological.org/gpp) or code generators like [GNU bison](https://www.gnu.org/software/bison/) or [SWIG](https://swig.org/). On Linux or POSIX systems **you can generate C code at runtime**, compile it as a plugin, then use [dlopen(3)](https://man7.org/linux/man-pages/man3/dlopen.3.html). Consider also [GNU lightning](https://www.gnu.org/software/lightning/) to generate code – Basile Starynkevitch Aug 09 '23 at 07:13
  • 2
    They can do anything, but not always with a pretty call syntax. (1) and (2) are easy, but you'll need to generate some boilerplate macros, limiting the max array length you can support. (3) can be doable with limitations: `a` and `b` need to be macros defined in a certain way, and they can't be inside parentheses, unless those parentheses are generated with another macro (so you can't do `(b+a)`, but can do `PARENS(b+a)`). In C++, you could avoid predefining `a` and `b` if you change the syntax to `VAR(a)`, `VAR(b)` (this requires some template magic). – HolyBlackCat Aug 09 '23 at 07:15
  • Not exactly but it can support cases 1 and 2 up to some predefined limit (like 16). I'm not sure about the third but c-preprocessor can execute any Turning machine but to fixed number of steps. But the limit grows exponentially with length of the file so it is unbounded in practice. – tstanisl Aug 09 '23 at 07:17
  • And [GCC](https://gcc.gnu.org/) or [GNU cpp](https://gcc.gnu.org/onlinedocs/cpp/index.html) has `__COUNTER__` – Basile Starynkevitch Aug 09 '23 at 07:18
  • 1
    Regarding replacing missing arguments with default values, check out https://stackoverflow.com/a/73934150/584518. – Lundin Aug 09 '23 at 08:40
  • 1
    Anyway this is all too broad and non-specific. For any macro `BLEH(whatever you like to type here)` you can do `#define BLEH(...) function(#__VA_ARGS__)`, passing the resulting string to a function doing advanced string expression parsing... Is it compile-time parsing? No. But you didn't specify that in the question. – Lundin Aug 09 '23 at 08:43
  • @BasileStarynkevitch And so do Clang and MSVC. `__COUNTER__` is effectively supported everywhere. – HolyBlackCat Aug 09 '23 at 09:54
  • Agreed my question was a bit too large in scope though your combined answers gave me lots of good suggestions. 1. (and therefore 2) can easily be resolved using `sizeof(int[]){__VA_ARGS__} / sizeof(int)`. Or perhaps `__COUNTER__` if my arguments aren't just of one type. The suggestion of run-time parsing from @Lundin is an interesting one I need to explore. That would give me lots of flexibility. – Lolo Aug 09 '23 at 10:58

0 Answers0