Search code examples
arrayscmacrospreprocessor

It is possible to call function or calculate in C preprocessor step?


I want to make array whose length is (int)log(macro constant) like

#define MACRO_NUM 100
int arr[(int)log(MACRO_NUM)];

But as you know, MSVC doesn't support variable-length array. So, declaring array, I can't use variable or function at index of array. It means every value determined in run-time couldn't become index of array. So I thought that preprocessor should do some kind of calculation before compilation if to do this possible.

So my question is

  1. Is my inference right?
  2. So is there any ways to make preprocessor calculate? Or preprocessor can do just only replacements.

I know there's another ways like dynamic allocation with pointer etc, but, I just wander ,as a student, It is possible way to do this with array and macro constant when variable-length array is not supported.


Solution

  • No, the preprocessor doesn't do calculations, only substitutions and the other usual preprocessor stuff.

    However, you can sometimes get a similar effect as follows. Pretty much anywhere in C that a compile-time constant is needed, you can use an arbitrary arithmetic expression whose operands are constants (which will be evaluated by the compiler, not the preprocessor). And a macro can be a convenient way to wrap such an expression, especially if it would otherwise be awkwardly long.

    As a trivial example, you can do

    #define SQUARE(x) ((x)*(x))
    int foo[SQUARE(6)];
    

    After preprocessing, this reads int foo[((6)*(6))]; and the compiler defines an array of length 36. The calculation was done by the compiler, not the preprocessor, but the effect is much the same.

    Now log isn't generally a function that the compiler can evaluate at compile time, but you can fake it:

    #define MY_LOG(x) ((x) < 10 ? 0 : (x) < 100 ? 1 : (x) < 1000 ? 2 : .....) 
    

    with as many more ?: as you need until you've exhausted the range of int or long or whatever. For log base ten it'll only be at most 10 or 20. And then you can do

    #define MACRO_NUM 100
    int arr[MY_LOG(MACRO_NUM)]
    

    and get an array of length 2.

    Just be careful that you don't ever use MY_LOG with an argument that has side effects!