所以,我需要一个常量值来表示int中的最大位数,并且需要在编译时计算它以传递给char数组的大小。
要添加更多细节:我正在使用的编译器/机器具有非常有限的C语言子集,因此没有std库可以工作,因为它们具有不受支持的功能。因此我不能使用INT_MIN / MAX,因为我既不能包含它们,也不能定义它们。
我需要一个计算大小的编译时表达式。我想出的公式是:
((sizeof(int)/ 2)* 3 + sizeof(int))+ 2
基于手工计算n字节整数略有成功。
sizeof(int) INT_MAX characters formula
2 32767 5 7
4 2147483647 10 12
8 9223372036854775807 19 22
答案 0 :(得分:2)
您正在寻找与所讨论的整数类型的最大值的对数相关的结果( 对数取决于您要计算其数字的表示的基数) 。您无法在编译时计算精确的对数,但您可以编写宏来为您的目的估计它们,或者为您的目的计算足够接近的上限。例如,请参阅How to compute log with the preprocessor。
知道你可以通过乘以适当的常数在不同的基数之间进行对数转换也是有用的。特别是,如果您知道数字的base- a 对数,并且您希望base- b 对数,则可以将其计算为
log b ( x )= log a ( x )/ log a 子>(b)中
但是你的情况比一般的情况要容易一些。对于不是可变长度数组的数组的维度,您需要一个"整数常量表达式"。此外,对于您在C实现中找到的任何内置整数类型,您的结果不需要超过两位数的精度(如果您想要二进制数字,则为三位数),并且看起来你只需要一个足够接近的上限。
此外,你从sizeof
运算符开始,它可以出现在整数常量表达式中,当应用于整数类型时,它给出了一个基数为256的对数值的上限。那种类型(假设CHAR_BIT
是8)。如果每个位都是一个值位,那么这个估计非常紧,但是有符号整数有一个符号位,它们也可能有填充位,所以这个边界对它们来说有点松散。
如果你想要一个二次幂基数的位数限制,那么你可以直接使用sizeof
。但是,我们假设您正在寻找十进制数字的数量。在数学上,int
的十进制表示中的最大位数是
N = ceil(log 10 (MAX_INT
))
或
N =楼层(日志 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 Computed N 1 127 3 3 2 32767 5 5 4 2147483648 10 10 8 ~9.223372037e+18 19 20
(INT_MAX
和True N
列中的值假设允许的有符号表示形式之一,并且没有填充位;如果表示包含填充位,则前者和可能两者都将更小。 )
我认为,如果你遇到一个8字节int
s的系统,你提供给你的数字阵列的额外一个字节不会让你失望。这种差异源于有符号的64位整数中具有(最多)63个值位与在这种情况下计算64位值的公式之间的差异,结果sizeof(int)
有点过多高估INT_MAX
的base-256 log。如果没有填充位,该公式会为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)
答案 1 :(得分:1)
我觉得你需要对此进行硬编码,主要是检查sizeof(int)
并查阅编译器文档,看看你实际拥有什么样的int
。 (所有C标准规定的是它不能小于short
,并且需要具有至少-32767到+32767的范围,并且可以选择1的补码,2的补码和有符号的幅度存储的方式是任意的,虽然大和小的字节序是常见的。)注意允许任意数量的填充位,所以你不能完全通用地计算小数位数来自sizeof
。
C不支持您需要的编译时可评估常量表达式的级别。
如此硬编码并使您的代码故意脆弱,以便编译器遇到您没有想到的情况时编译失败。
您可以使用constexpr
和元编程技术在C ++中解决此问题。
答案 2 :(得分:1)
int
可能产生的小数位数的上限取决于INT_MIN
。
// Mathematically
max_digits = ceil(log10(-INT_MAX))
使用int
的位宽更容易,因为它接近-INT_MIN
的对数。 sizeof(int)*CHAR_BIT - 1
是int
中值位的最大数量。
// Mathematically
max_digits = ceil((sizeof(int)*CHAR_BIT - 1)* log10(2))
// log10(2) --> ~ 0.30103
在稀有机器上,int
有填充,因此上述内容将高估。
作为一个宏,执行整数数学并为 ceiling
添加1#include <stdlib.h>
#define INT_DIGIT10_WIDTH ((sizeof(int)*CHAR_BIT - 1)/3 + 1)
要考虑签名和空字符添加2,请使用以下内容。使用非常紧密的log10(2)分数来不过度计算缓冲区需求:
#define INT_STRING_SIZE ((sizeof(int)*CHAR_BIT - 1)*28/93 + 3)
任何基数降至基数2所需的位数需要如下所示。有趣的是需要+2而不是+1。考虑基数2中的2位有符号数可以是"-10"
,大小为4.
#define INT_STRING2_SIZE ((sizeof(int)*CHAR_BIT + 2)
答案 3 :(得分:0)
((sizeof(int) / 2) * 3 + sizeof(int)) + 2
是我提出的公式。 +2用于负号和空终止符。
答案 4 :(得分:0)
如果我们假设整数值是2个,4个或8个字节,并且如果我们确定相应的数字是5,10,20,那么产生精确值的整数常量表达式可以写成如下: / p>
const int digits = (sizeof(int)==8) ? 20 : ((sizeof(int)==4) ? 10 : 5);
int testArray[digits];
我希望我没有错过任何必要的东西。我已经在文件范围内对此进行了测试。