因此,我需要一个常量值来表示 int 中的最大位数,并且需要在编译时计算它以传递给 char 数组的大小。
添加更多细节:我正在使用的编译器/机器具有非常有限的 C 语言子集,因此没有一个 std 库可以工作,因为它们具有不受支持的功能。因此,我不能使用 INT_MIN/MAX,因为我既不能包含它们,也不能定义它们。
我需要一个计算大小的编译时表达式。我想出的公式是:
((sizeof(int) / 2) * 3 + sizeof(int)) + 2
Run Code Online (Sandbox Code Playgroud)
基于手工计算的 n 字节整数略微成功。
sizeof(int) INT_MAX characters formula
2 32767 5 7
4 2147483647 10 12
8 9223372036854775807 19 22
Run Code Online (Sandbox Code Playgroud)
您正在寻找与所讨论的整数类型的最大值的对数相关的结果(该对数取决于您要计算其数字的表示形式的基数)。您无法在编译时计算精确的对数,但您可以编写宏来根据您的目的对它们进行足够接近的估计,或者为您的目的计算足够接近的上限。例如,请参阅如何使用预处理器计算日志。
了解您可以通过乘以适当的常数在不同底数的对数之间进行转换也很有用。特别是,如果您知道一个数字的底数a对数并且想要底数b对数,则可以将其计算为
log b ( x ) = log a ( x ) / log a (b)
不过,您的情况比一般情况要容易一些。对于不是变长数组的数组维数,需要一个“整数常量表达式”。此外,对于您将在 C 实现中找到的任何内置整数类型,您的结果不需要超过两位的精度(如果您想要二进制位数,则为三位),而且似乎您只需要一个足够接近的上限。
此外,您可以从sizeof运算符中获得领先优势,它可以出现在整数常量表达式中,并且当应用于整数类型时,会为您提供该类型值的以 256 为底的对数的上限(假设CHAR_BIT为 8) . 如果每个位都是值位,则此估计非常严格,但有符号整数有一个符号位,并且它们也可能有填充位,因此这个界限对它们来说有点松散。
如果您想在 2 的幂的基数中限制位数,那么您可以sizeof直接使用。不过,让我们假设您正在寻找小数位数。在数学上,an 的十进制表示中的最大位数int是
N = ceil(log 10 ( MAX_INT))
或者
N = floor(log 10 ( MAX_INT)) + 1
前提是MAX_INT它不是 10 的幂。让我们用以 256 为底的对数表示:
N = floor(log 256 ( MAX_INT) / log 256 (10) ) + 1
现在,log 256 (10) 不能是整数常量表达式的一部分,但它或其倒数可以预先计算:1 / log 256 (10) = 2.40824(相当好的近似值;实际值略小) . 现在,让我们用它来重写我们的表达式:
N <= floor( sizeof(int) * 2.40824 ) + 1
这还不是整数常量表达式,但已经接近了。这个表达式是一个整数常量表达式,并且是一个足够好的近似值来满足您的目的:
N = 241 * sizeof(int) / 100 + 1
以下是各种整数大小的结果:
sizeof(int) INT_MAX True N 计算 N
1 127 3 3
2 32767 5 5
4 2147483648 10 10
8 ~9.223372037e+18 19 20
(INT_MAX和True N列中的值假设允许的有符号表示形式之一,并且没有填充位;如果表示包含填充位,前者和两者可能都会更小。)
我认为,万一您遇到具有 8 字节ints的系统,那么您为 digit 数组提供的额外一个字节不会让您失望。这种差异源于在一个有符号的 64 位整数中(最多)63 个值位与在这种情况下计算 64 个值位的公式之间的差异,结果sizeof(int)有点高估了基数-256 日志INT_MAX。如果unsigned int没有填充位,该公式给出了大小至少为 8 的精确结果。
作为宏,则:
// Expands to an integer constant expression evaluating to a close upper bound
// on the number the number of decimal digits in a value expressible in the
// integer type given by the argument (if it is a type name) or the the integer
// type of the argument (if it is an expression). The meaning of the resulting
// expression is unspecified for other arguments.
#define DECIMAL_DIGITS_BOUND(t) (241 * sizeof(t) / 100 + 1)
Run Code Online (Sandbox Code Playgroud)