j4x*_*j4x 14 c string int type-conversion
我想知道是否这是一种确定打印小数的最大字符数的简单方法int.
我知道<limits.h>包含了诸如定义INT_MAX是说,最高值 int可以假设,但它不是我想要的.
我希望能够做到这样的事情:
int get_int( void )
{
char draft[ MAX_CHAR_OF_A_DECIMAL_INT ];
fgets( draft, sizeof( draft ), stdin );
return strtol( draft, NULL, 10 );
}
Run Code Online (Sandbox Code Playgroud)
但是如何以MAX_CHAR_OF_A_DECIMAL_INT便携和低调的方式找到价值呢?
谢谢!
R..*_*R.. 12
如果假设CHAR_BIT是8(在POSIX上是必需的,那么任何针对POSIX系统的代码以及任何其他主流系统如Windows的安全假设)都是廉价的安全公式3*sizeof(int)+2.如果没有,你可以制作它3*sizeof(int)*CHAR_BIT/8+2,或者有一个稍微简单的版本.
如果您对其工作原因感兴趣,sizeof(int)则基本上是INT_MAX(大致记录基数2 ^ CHAR_BIT)的对数,并且不同基数(例如,基数10)的对数之间的转换只是乘法.特别地,3是对数基数10为256的整数近似/上限.
+2用于说明可能的符号和空终止.
我不知道在普通的 ANSI-C 中做你想做的事情是否有什么技巧,但在 C++ 中你可以很容易地使用模板元编程来做:
#include <iostream>
#include <limits>
#include <climits>
template< typename T, unsigned long N = INT_MAX >
class MaxLen
{
public:
enum
{
StringLen = MaxLen< T, N / 10 >::StringLen + 1
};
};
template< typename T >
class MaxLen< T, 0 >
{
public:
enum
{
StringLen = 1
};
};
Run Code Online (Sandbox Code Playgroud)
您可以从纯 C 代码中调用它,创建一个额外的 C++ 函数,如下所示:
extern "C"
int int_str_max( )
{
return MaxLen< int >::StringLen;
}
Run Code Online (Sandbox Code Playgroud)
这具有零执行时间开销并计算所需的确切空间。
您可以使用以下内容测试上述模板:
int main( )
{
std::cout << "Max: " << std::numeric_limits< short >::max( ) << std::endl;
std::cout << "Digits: " << std::numeric_limits< short >::digits10 << std::endl;
std::cout << "A \"short\" is " << sizeof( short ) << " bytes." << std::endl
<< "A string large enough to fit any \"short\" is "
<< MaxLen< short, SHRT_MAX >::StringLen << " bytes wide." << std::endl;
std::cout << "Max: " << std::numeric_limits< int >::max( ) << std::endl;
std::cout << "Digits: " << std::numeric_limits< int >::digits10 << std::endl;
std::cout << "An \"int\" is " << sizeof( int ) << " bytes." << std::endl
<< "A string large enough to fit any \"int\" is "
<< MaxLen< int >::StringLen << " bytes wide." << std::endl;
std::cout << "Max: " << std::numeric_limits< long >::max( ) << std::endl;
std::cout << "Digits: " << std::numeric_limits< long >::digits10 << std::endl;
std::cout << "A \"long\" is " << sizeof( long ) << " bytes." << std::endl
<< "A string large enough to fit any \"long\" is "
<< MaxLen< long, LONG_MAX >::StringLen << " bytes wide." << std::endl;
return 0;
}
Run Code Online (Sandbox Code Playgroud)
输出是:
Max: 32767
Digits: 4
A "short" is 2 bytes.
A string large enough to fit any "short" is 6 bytes wide.
Max: 2147483647
Digits: 9
An "int" is 4 bytes.
A string large enough to fit any "int" is 11 bytes wide.
Max: 9223372036854775807
Digits: 18
A "long" is 8 bytes.
A string large enough to fit any "long" is 20 bytes wide.
Run Code Online (Sandbox Code Playgroud)
std::numeric_limits< T >::digits10与 MaxLen< T, N >::StringLen 的值略有不同,因为如果不能达到 '9',前者不考虑数字。当然,如果您不在乎在某些情况下浪费单个字节,您可以使用它并简单地添加两个。编辑:
有些人可能觉得很奇怪,包括<climits>. 如果您可以使用 C++11 进行计数,您将不需要它,并且会获得额外的简单性:
#include <iostream>
#include <limits>
template< typename T, unsigned long N = std::numeric_limits< T >::max( ) >
class MaxLen
{
public:
enum
{
StringLen = MaxLen< T, N / 10 >::StringLen + 1
};
};
template< typename T >
class MaxLen< T, 0 >
{
public:
enum
{
StringLen = 1
};
};
Run Code Online (Sandbox Code Playgroud)
现在你可以使用
MaxLen< short >::StringLen
Run Code Online (Sandbox Code Playgroud)
代替
MaxLen< short, SHRT_MAX >::StringLen
Run Code Online (Sandbox Code Playgroud)
很好,不是吗?
最简单的规范且可以说是最可移植的方法是询问snprintf()将需要多少空间:
char sbuf[2];
int ndigits;
ndigits = snprintf(sbuf, (size_t) 1, "%lld", (long long) INT_MIN);
Run Code Online (Sandbox Code Playgroud)
使用intmax_t和的可移植性稍差一些%j:
ndigits = snprintf(sbuf, (size_t) 1, "%j", (intmax_t) INT_MIN);
Run Code Online (Sandbox Code Playgroud)
人们可能会认为这样做虽然在运行时花费太高,但它可以适用于任何值,而不仅仅是任何整数类型的MIN / MAX值。
当然,您也可以使用简单的递归函数直接计算给定整数将需要用Base 10表示法表示的位数:
unsigned int
numCharsB10(intmax_t n)
{
if (n < 0)
return numCharsB10((n == INTMAX_MIN) ? INTMAX_MAX : -n) + 1;
if (n < 10)
return 1;
return 1 + numCharsB10(n / 10);
}
Run Code Online (Sandbox Code Playgroud)
但这当然也需要运行时的CPU,即使是内联的,也可能要少一些snprintf()。
@R。上面的答案虽然或多或少是错误的,但却是正确的。这是一些经过很好测试和高度可移植的宏的正确派生,这些宏在编译时使用sizeof()进行了计算,并使用@R的初始措辞进行了小幅修正,从而开始了计算:
首先,我们可以轻松地看到(或显示)它sizeof(int)的对数基数2 UINT_MAX除以一个单位sizeof()(8,aka CHAR_BIT)表示的位数:
sizeof(int)== log2(UINT_MAX)/ 8
因为UINT_MAX当然只有2 ^(sizeof(int)* 8)),而log2(x)是2 ^ x的倒数。
我们可以使用标识“ logb(x)= log(x)/ log(b)”(其中log()是自然对数)来查找其他碱基的对数。例如,您可以使用以下公式计算“ x”的“ log base 2”:
log2(x)= log(x)/ log(2)
并且:
log10(x)= log(x)/ log(10)
因此,我们可以推断出:
log10(v)= log2(v)/ log2(10)
现在,我们最后想要的是log的10为底UINT_MAX,因此log2(10)大约为3,并且由于我们从上面知道log2()的含义sizeof(),我们可以说log10(UINT_MAX)大约是:
log10(2 ^(sizeof(int)* 8))〜=(sizeof(int)* 8)/ 3
不过,这并不是完美的,尤其是因为我们真正想要的是最高值,但是需要进行一些小的调整以将log2(10)的整数舍入为3,我们可以通过将log2(10)首先加到log2项来获得所需的值,然后将任何较大的整数从结果中减去1,得到此“足够好”的表达式:
#if 0
#define __MAX_B10STRLEN_FOR_UNSIGNED_TYPE(t) \
((((sizeof(t) * CHAR_BIT) + 1) / 3) - ((sizeof(t) > 2) ? 1 : 0))
#endif
Run Code Online (Sandbox Code Playgroud)
更好的是,我们可以将第一个log2()项乘以1 / log2(10)(乘以除数的倒数与除以除数相同),这样做可以找到更好的整数近似。最近,我在阅读肖恩·安德森(Sean Anderson)的bithacks时遇到了这个建议:http ://graphics.stanford.edu/~seander/bithacks.html#IntegerLog10
为了使整数数学达到最佳近似值,我们需要找到代表倒数的理想比率。这可以通过在将2的幂的某个合理范围内搜索所需的1 / log2(10)乘以2的连续幂的最小分数部分来找到,例如使用以下小AWK脚本:
awk 'BEGIN {
minf=1.0
}
END {
for (i = 1; i <= 31; i++) {
a = 1.0 / (log(10) / log(2)) * 2^i
if (a > (2^32 / 32))
break;
n = int(a)
f = a - (n * 1.0)
if (f < minf) {
minf = f
minn = n
bits = i
}
# printf("a=%f, n=%d, f=%f, i=%d\n", a, n, f, i)
}
printf("%d + %f / %d, bits=%d\n", minn, minf, 2^bits, bits)
}' < /dev/null
1233 + 0.018862 / 4096, bits=12
Run Code Online (Sandbox Code Playgroud)
因此,我们可以得到一个很好的整数近似值:将log2(v)值乘以1 / log2(10),再乘以1233,然后右移12(当然2 ^ 12是4096):
log10(UINT_MAX)〜=(((sizeof(int)* 8)+1)* 1233 >> 12
并且,再加上一个以求出最高值,就摆脱了摆弄奇数值的需要:
#define __MAX_B10STRLEN_FOR_UNSIGNED_TYPE(t) \
(((((sizeof(t) * CHAR_BIT)) * 1233) >> 12) + 1)
/*
* for signed types we need room for the sign, except for int64_t
*/
#define __MAX_B10STRLEN_FOR_SIGNED_TYPE(t) \
(__MAX_B10STRLEN_FOR_UNSIGNED_TYPE(t) + ((sizeof(t) == 8) ? 0 : 1))
/*
* NOTE: this gives a warning (for unsigned types of int and larger) saying
* "comparison of unsigned expression < 0 is always false", and of course it
* is, but that's what we want to know (if indeed type 't' is unsigned)!
*/
#define __MAX_B10STRLEN_FOR_INT_TYPE(t) \
(((t) -1 < 0) ? __MAX_B10STRLEN_FOR_SIGNED_TYPE(t) \
: __MAX_B10STRLEN_FOR_UNSIGNED_TYPE(t))
Run Code Online (Sandbox Code Playgroud)
而通常,编译器会在编译时评估我的__MAX_B10STRLEN_FOR_INT_TYPE()宏变为的表达式。当然,我的宏总是计算给定类型的整数所需的最大空间,而不是特定整数值所需的确切空间。