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
- Is my inference right?
- 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.
CodePudding user response:
If MACRO_NUM is guaranteed to be a compile-time constant (such as 100) and by (int)log(MACRO_NUM) you mean "the largest k such that 2k ≤ MACRO_NUM", then it can be done (but not by getting the preprocessor to do a computation, which is not really possible):
#define LOG_MACRO_NUM ((MACRO_NUM >= (1UL<<1)) \
(MACRO_NUM >= (1UL<<2)) \
(MACRO_NUM >= (1UL<<3)) \
(MACRO_NUM >= (1UL<<4)) \
(MACRO_NUM >= (1UL<<5)) \
(MACRO_NUM >= (1UL<<6)) \
(MACRO_NUM >= (1UL<<7)) \
(MACRO_NUM >= (1UL<<8)) \
(MACRO_NUM >= (1UL<<9)) \
(MACRO_NUM >= (1UL<<10)) \
(MACRO_NUM >= (1UL<<11)) \
(MACRO_NUM >= (1UL<<12)) \
(MACRO_NUM >= (1UL<<13)) \
(MACRO_NUM >= (1UL<<14)) \
(MACRO_NUM >= (1UL<<15)) \
(MACRO_NUM >= (1UL<<16)) \
(MACRO_NUM >= (1UL<<17)) \
(MACRO_NUM >= (1UL<<18)) \
(MACRO_NUM >= (1UL<<19)) \
(MACRO_NUM >= (1UL<<20)) \
(MACRO_NUM >= (1UL<<21)) \
(MACRO_NUM >= (1UL<<22)) \
(MACRO_NUM >= (1UL<<23)) \
(MACRO_NUM >= (1UL<<24)) \
(MACRO_NUM >= (1UL<<25)) \
(MACRO_NUM >= (1UL<<26)) \
(MACRO_NUM >= (1UL<<27)) \
(MACRO_NUM >= (1UL<<28)) \
(MACRO_NUM >= (1UL<<29)) \
(MACRO_NUM >= (1UL<<30)) \
(MACRO_NUM >= (1UL<<31)))
If you want to handle numbers greater than 32 bits, continue... :-)
Of course, that basic pattern will work with other bases, but base 2 is a bit easier to work with.
CodePudding user response:
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!
