在C语言中,编译时是否可以计算预处理器值的阶乘值?

rjee0c15  于 2023-02-15  发布在  其他
关注(0)|答案(3)|浏览(139)
#define num 7  \\ user can change this
#define size ????  \\I want this value (factorial of num) to be computed during compile time

int array[size][num];

我想全局定义array,但是它的大小依赖于预处理器num的值,所以我想在编译时确定值(num的阶乘)。
有可能吗?如果有,怎么做?

eoigrqb6

eoigrqb61#

在单独的.h文件(例如fc. h)中:

#if num == 1
#define sum 1
#elif num == 2
#define sum 2
#elif num == 3
#define sum 6
#elif num == 4
#define sum 24
#elif num == 5
#define sum 120
#elif num == 6
#define sum 720
#elif num == 7
#define sum 5040
#elif num == 8
#define sum 40320
#elif num == 9
#define sum 362880
#else
#error wrong number
#endif

用途

#define num 7
#include "fc.h"

int array[sum][num];
kpbwa7wx

kpbwa7wx2#

我通常编写一个简短的shell脚本来预先计算三元表达式的值。

// $ fac() { r=1; for ((i=$1;i!=0;--i)); do ((r*=i)); done; echo $r; }; for ((i=1;i<10;++i)); do echo "i == $i ? $(fac $i) : \\"; done
#define FACTORIAL(x) \
i == 1 ? 1 : \
i == 2 ? 2 : \
i == 3 ? 6 : \
i == 4 ? 24 : \
i == 5 ? 120 : \
i == 6 ? 720 : \
i == 7 ? 5040 : \
i == 8 ? 40320 : \
i == 9 ? 362880 : \
-1

int array[FACTORIAL(3)][3];
ergxz8rk

ergxz8rk3#

您可以手动将(x) * (((x)-1)>0?((x)-1):1) * (((x)-2)>0?((x)-2):1) ...之类的内容放入宏中,您只需要进行几次迭代,因为阶乘增长非常快,并且支持的最大整数通常只有64位宽。
虽然如上所示的表达式可能看起来很复杂,但对于整型常量表达式x(如11+2sizeof(0)*3),它保证生成整型常量表达式,即适合初始化静态数组大小、位字段大小和大小写标签的表达式。(例如142u0x1000ull),则表达式也是预处理器可识别的,即,适合作为#if预处理器条件的自变量。
那么你怎么能得到这样一个宏呢?
首先,你需要一个阶乘参数的上限,它不会溢出一个unsigned long long(预处理器和C编译器保证支持的最大值,通常为64位宽)。
你可以用一些

#include <stdio.h>
unsigned long long factorial(unsigned long long X){ if(X<=1) return 1; return X*factorial(X-1); }
int main(){
    int i=2;
    for(; i<100 && factorial(i-1)<factorial(i); i++){ if(0) printf("%016llx \n", factorial(i)); }
    printf("%d\n", i-1); //22
}

并且对于64位无符号长型long是22。
知道它是22,就可以生成宏:

printf("#define FACTORIAL(X) ((X)>22 || (X)<0 ? 0 : (1 ");
 for(int i=0; i<22; i++) printf(" * ((int)+(X)-%d > 0 ? (X)-%dULL : 1)", i, i);
 printf("))\n");

上面的指纹

#define FACTORIAL(X) ((X)>22 ? 0 : (1  * ((int)+(X)-0 > 0 ? (X)-0ULL : 1) * ((int)+(X)-1 > 0 ? (X)-1ULL : 1) * ((int)+(X)-2 > 0 ? (X)-2ULL : 1) * ((int)+(X)-3 > 0 ? (X)-3ULL : 1) * ((int)+(X)-4 > 0 ? (X)-4ULL : 1) * ((int)+(X)-5 > 0 ? (X)-5ULL : 1) * ((int)+(X)-6 > 0 ? (X)-6ULL : 1) * ((int)+(X)-7 > 0 ? (X)-7ULL : 1) * ((int)+(X)-8 > 0 ? (X)-8ULL : 1) * ((int)+(X)-9 > 0 ? (X)-9ULL : 1) * ((int)+(X)-10 > 0 ? (X)-10ULL : 1) * ((int)+(X)-11 > 0 ? (X)-11ULL : 1) * ((int)+(X)-12 > 0 ? (X)-12ULL : 1) * ((int)+(X)-13 > 0 ? (X)-13ULL : 1) * ((int)+(X)-14 > 0 ? (X)-14ULL : 1) * ((int)+(X)-15 > 0 ? (X)-15ULL : 1) * ((int)+(X)-16 > 0 ? (X)-16ULL : 1) * ((int)+(X)-17 > 0 ? (X)-17ULL : 1) * ((int)+(X)-18 > 0 ? (X)-18ULL : 1) * ((int)+(X)-19 > 0 ? (X)-19ULL : 1) * ((int)+(X)-20 > 0 ? (X)-20ULL : 1) * ((int)+(X)-21 > 0 ? (X)-21ULL : 1)))

你可以测试这个宏是否有预处理器可以识别的整数:

#if FACTORIAL(1)!=1 || FACTORIAL(6)!=720 || FACTORIAL(22) != 0xeea4c2b3e0d80000
   #error ""
#endif

对于预处理器无法识别的整型常量表达式:

_Static_assert(FACTORIAL(6*sizeof(char))==720,"");

相关问题