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
- 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.
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):
Note: See below for a much more compact version.
#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 64-bit numbers, change 1UL to 1ULL
* and continue the pattern up to 63.
*/
Live on coliru
This can be made much more compact using the Boost preprocessor library, which unlike most of Boost works with both C and C++. It's a separate header-only library, so it can be installed independently by just copying the directory of header files. That reduces the above ugliness to:
#include <stdio.h>
#include <boost/preprocessor/repetition/repeat_from_to.hpp>
#define CHECK_POWER(Z,I,V) + ((V) >= (1ULL << I))
#define ILOGB(C) (BOOST_PP_REPEAT_FROM_TO(1, 32, CHECK_POWER, C))
/* Declared at file scope to show that the macro produces a
* compile-time constant; static VLAs are not allowed
* even on compilers which implement VLAs.
*/
int arr[ILOGB(4127)] = {0};
int main(void) {
printf("array has %zu elements.\n", sizeof arr / sizeof *arr);
}
Live on coliru