Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/string/5.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
ANSI-C:打印十进制整数的最大字符数_C_String_Int_Type Conversion - Fatal编程技术网

ANSI-C:打印十进制整数的最大字符数

ANSI-C:打印十进制整数的最大字符数,c,string,int,type-conversion,C,String,Int,Type Conversion,我想知道这是否是确定打印十进制int的最大字符数的简单方法 我知道包含像INT\u MAX这样的定义,即INT可以假定的最大值,但这不是我想要的 我希望能够做到以下几点: int get_int( void ) { char draft[ MAX_CHAR_OF_A_DECIMAL_INT ]; fgets( draft, sizeof( draft ), stdin ); return strtol( draft, NULL, 10 ); } int main( )

我想知道这是否是确定打印十进制
int
的最大字符数的简单方法

我知道
包含像
INT\u MAX
这样的定义,即INT可以假定的最大值,但这不是我想要的

我希望能够做到以下几点:

int get_int( void )
{
    char draft[ MAX_CHAR_OF_A_DECIMAL_INT ];

    fgets( draft, sizeof( draft ), stdin );
    return strtol( draft, NULL, 10 );
}
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;
}
但是,如何以一种便携且低开销的方式找到
MAX\u CHAR\u of A\u DECIMAL\u INT
的值呢


谢谢

如果您假设
CHAR\u BIT
是8(POSIX上需要,因此对于任何针对POSIX系统以及任何其他主流系统(如Windows)的代码都是安全的),那么便宜的安全公式是
3*sizeof(int)+2
。如果没有,您可以将其设置为
3*sizeof(int)*CHAR\u BIT/8+2
,或者有一个稍微简单的版本

如果您对其工作原理感兴趣,
sizeof(int)
本质上是
int\u MAX
的对数(大致为对数基数2^CHAR\u位),不同基数的对数之间的转换(例如,到基数10)就是乘法。特别是,3是256的对数基数10上的整数近似值/上限


< + 2是一个可能的符号和空终止。

< p>我不知道在平原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
    };
};
  • 注意与
    std::numeric_limits::digits10
    和MaxLen::StringLen稍有不同的值,因为前者不考虑不能达到“9”的数字。 当然,如果您不介意在某些情况下浪费一个字节,您可以使用它并简单地添加两个字节

编辑:

有些人可能会觉得奇怪,包括
。 如果您可以使用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
    };
};
#包括
#包括
模板::max()>
MaxLen类
{
公众:
枚举
{
StringLen=MaxLen::StringLen+1
};
};
模板
类MaxLen
{
公众:
枚举
{
StringLen=1
};
};
现在你可以使用

MaxLen< short >::StringLen
MaxLen::StringLen
而不是

MaxLen< short, SHRT_MAX >::StringLen
MaxLen::StringLen

很好,不是吗?

最简单的规范化且可以说是最可移植的方法是询问
snprintf()
需要多少空间:

char sbuf[2];
int ndigits;

ndigits = snprintf(sbuf, (size_t) 1, "%lld", (long long) INT_MIN);
可能使用
intmax\u t
%j
时便携性稍差:

ndigits = snprintf(sbuf, (size_t) 1, "%j", (intmax_t) INT_MIN);

可以认为运行时代价太高,但它可以用于任何值,而不是任何整数类型的最小/最大值。 当然,您也可以使用简单的递归函数直接计算给定整数需要以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);
}
更好的是,我们可以将第一个log2()项乘以1/log2(10)(乘以除数的倒数等于除以除数),这样做可以找到更好的整数近似值。我最近(再次?)在阅读肖恩·安德森(Sean Anderson)的bithacks时遇到了这个建议:

为了使整数数学尽可能达到最佳近似,我们需要找到表示倒数的理想比率。这可以通过搜索期望值1/log2(10)乘以2的连续幂的最小小数部分来找到,在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
awk'开始{
minf=1.0
}
结束{
对于(i=1;i(2^32/32))
打破
n=int(a)
f=a-(n*1.0)
if(f
所以我们可以得到一个很好的整数近似值,将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))
#为_UNSIGNED_类型(t)定义u MAX_B10STRLEN_\
((((((t)大小)(字符位)))
/*
*对于签名类型,我们需要为签名留出空间,int64\t除外
*/
#定义签名类型(t)的最大字符串\
(uuu MAX_B10STRLEN_u表示无符号类型(t)+(sizeof(t)==8)?0:1))
/*
*注意:这会给出一个警告(对于int和更大的无符号类型)说
*“无符号表达式<0的比较总是错误的”,当然
*是,但这就是我们想要知道的(如果类型't'确实是无符号的)!
*/
#为内部类型(t)定义最大值\
((t)-1<0)?符号类型(t)的最大值\
:uuuu MAX_B10STRLEN_u用于无符号类型(t))
然而,编译器通常会在编译时计算表达式my
\uu MAX\u B10STRLEN\u FOR\u INT\u TYPE()
宏。当然,我的宏总是计算给定类型整数所需的最大空间,而不是特定整数值所需的确切空间。

接受答案后(2年以上)

以下分数10/33完全满足未添加的
int8\u t
int16\u t
int32\u t
int128\u t
的需要。对于
int64\t
,只有1个
char
额外字符。对于小于等于
int362\u t
的所有整数大小,精确或大于1。除此之外,可能还不止一个

#include <limits.h>
#define MAX_CHAR_LEN_DECIMAL_INTEGER(type) (10*sizeof(type)*CHAR_BIT/33 + 2)
#define MAX_CHAR_SIZE_DECIMAL_INTEGER(type) (10*sizeof(type)*CHAR_BIT/33 + 3)

int get_int( void ) {
                                            //   + 1 for the \n of fgets()
  char draft[MAX_CHAR_SIZE_DECIMAL_INTEGER(long) + 1];  //**

  fgets(draft, sizeof draft, stdin);
  return strtol(draft, NULL, 10);
}

您可以计算u的位数
    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
#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))
#include <limits.h>
#define MAX_CHAR_LEN_DECIMAL_INTEGER(type) (10*sizeof(type)*CHAR_BIT/33 + 2)
#define MAX_CHAR_SIZE_DECIMAL_INTEGER(type) (10*sizeof(type)*CHAR_BIT/33 + 3)

int get_int( void ) {
                                            //   + 1 for the \n of fgets()
  char draft[MAX_CHAR_SIZE_DECIMAL_INTEGER(long) + 1];  //**

  fgets(draft, sizeof draft, stdin);
  return strtol(draft, NULL, 10);
}
  char draft[2*(MAX_CHAR_SIZE_DECIMAL_INTEGER(long) + 1)];
  fgets(draft, sizeof draft, stdin);
#include <limits.h>
#include <stdio.h>
#include <math.h>

int main(void){
  printf("%d %d\n", INT_MAX, (int)floor(log10(INT_MAX)) + 3);

  return 0;
}
#include <limits.h>

#define xstr(s) str(s)
#define str(s) #s
#define INT_STR_MAX sizeof(xstr(INT_MAX))

char buffer[INT_STR_MAX];
$ gcc -E -o str.cpp str.c
$ grep buffer str.cpp
char buffer[sizeof("2147483647")];

$ gcc -S -o str.S str.c
$ grep buffer str.S
    .comm   buffer,11,1
#include <limits.h>
#include <stdio.h>
#include <stdlib.h>

#define COMMON_LOG_OF_2 0.301029995663981

#define MAX_DECIMAL_DIGITS_UCHAR        ((unsigned) (sizeof (unsigned char     ) * 8 * COMMON_LOG_OF_2) + 1)
#define MAX_DECIMAL_DIGITS_USHORT       ((unsigned) (sizeof (unsigned short    ) * 8 * COMMON_LOG_OF_2) + 1)
#define MAX_DECIMAL_DIGITS_UINT         ((unsigned) (sizeof (unsigned int      ) * 8 * COMMON_LOG_OF_2) + 1)
#define MAX_DECIMAL_DIGITS_ULONG        ((unsigned) (sizeof (unsigned long     ) * 8 * COMMON_LOG_OF_2) + 1)
#define MAX_DECIMAL_DIGITS_ULONGLONG    ((unsigned) (sizeof (unsigned long long) * 8 * COMMON_LOG_OF_2) + 1)
#define MAX_DECIMAL_DIGITS_UINT128      ((unsigned) (sizeof (unsigned __int128 ) * 8 * COMMON_LOG_OF_2) + 1)

#define MAX_DECIMAL_DIGITS_CHAR         (1 + MAX_DECIMAL_DIGITS_UCHAR    )
#define MAX_DECIMAL_DIGITS_SHORT        (1 + MAX_DECIMAL_DIGITS_USHORT   )
#define MAX_DECIMAL_DIGITS_INT          (1 + MAX_DECIMAL_DIGITS_UINT     )
#define MAX_DECIMAL_DIGITS_LONG         (1 + MAX_DECIMAL_DIGITS_ULONG    )
#define MAX_DECIMAL_DIGITS_LONGLONG     (1 + MAX_DECIMAL_DIGITS_ULONGLONG)
#define MAX_DECIMAL_DIGITS_INT128       (1 + MAX_DECIMAL_DIGITS_UINT128  )

int main (void)
{
    char IntegerString[MAX_DECIMAL_DIGITS_INT + 1];

    printf ("MAX_DECIMAL_DIGITS_UCHAR     = %2u\n",MAX_DECIMAL_DIGITS_UCHAR    );
    printf ("MAX_DECIMAL_DIGITS_USHORT    = %2u\n",MAX_DECIMAL_DIGITS_USHORT   );
    printf ("MAX_DECIMAL_DIGITS_UINT      = %2u\n",MAX_DECIMAL_DIGITS_UINT     );
    printf ("MAX_DECIMAL_DIGITS_ULONG     = %2u\n",MAX_DECIMAL_DIGITS_ULONG    );
    printf ("MAX_DECIMAL_DIGITS_ULONGLONG = %2u\n",MAX_DECIMAL_DIGITS_ULONGLONG);
    printf ("MAX_DECIMAL_DIGITS_UINT128   = %2u\n",MAX_DECIMAL_DIGITS_UINT128  );

    printf ("MAX_DECIMAL_DIGITS_CHAR      = %2u\n",MAX_DECIMAL_DIGITS_CHAR     );
    printf ("MAX_DECIMAL_DIGITS_SHORT     = %2u\n",MAX_DECIMAL_DIGITS_SHORT    );
    printf ("MAX_DECIMAL_DIGITS_INT       = %2u\n",MAX_DECIMAL_DIGITS_INT      );
    printf ("MAX_DECIMAL_DIGITS_LONG      = %2u\n",MAX_DECIMAL_DIGITS_LONG     );
    printf ("MAX_DECIMAL_DIGITS_LONGLONG  = %2u\n",MAX_DECIMAL_DIGITS_LONGLONG );
    printf ("MAX_DECIMAL_DIGITS_INT128    = %2u\n",MAX_DECIMAL_DIGITS_INT128   );

    sprintf (IntegerString,"%d",INT_MAX);
    printf ("INT_MAX       = %d\n",INT_MAX);
    printf ("IntegerString = %s\n",IntegerString);

    sprintf (IntegerString,"%d",INT_MIN);
    printf ("INT_MIN       = %d\n",INT_MIN);
    printf ("IntegerString = %s\n",IntegerString);

    return EXIT_SUCCESS;
}
#include <limits.h>
#include <stdio.h>
#include <stdlib.h>

#define LOG2_x_2_11 616 // log(2) * 2^11

#define MAX_DECIMAL_DIGITS_UCHAR        (((sizeof (unsigned char     ) * LOG2_x_2_11) >> 8) + 1)
#define MAX_DECIMAL_DIGITS_USHORT       (((sizeof (unsigned short    ) * LOG2_x_2_11) >> 8) + 1)
#define MAX_DECIMAL_DIGITS_UINT         (((sizeof (unsigned int      ) * LOG2_x_2_11) >> 8) + 1)
#define MAX_DECIMAL_DIGITS_ULONG        (((sizeof (unsigned long     ) * LOG2_x_2_11) >> 8) + 1)
#define MAX_DECIMAL_DIGITS_ULONGLONG    (((sizeof (unsigned long long) * LOG2_x_2_11) >> 8) + 1)
#define MAX_DECIMAL_DIGITS_UINT128      (((sizeof (unsigned __int128 ) * LOG2_x_2_11) >> 8) + 1)

#define MAX_DECIMAL_DIGITS_CHAR     (1 + MAX_DECIMAL_DIGITS_UCHAR    )
#define MAX_DECIMAL_DIGITS_SHORT    (1 + MAX_DECIMAL_DIGITS_USHORT   )
#define MAX_DECIMAL_DIGITS_INT      (1 + MAX_DECIMAL_DIGITS_UINT     )
#define MAX_DECIMAL_DIGITS_LONG     (1 + MAX_DECIMAL_DIGITS_ULONG    )
#define MAX_DECIMAL_DIGITS_LONGLONG (1 + MAX_DECIMAL_DIGITS_ULONGLONG)
#define MAX_DECIMAL_DIGITS_INT128   (1 + MAX_DECIMAL_DIGITS_UINT128  )

int main (void)
{
    char IntegerString[MAX_DECIMAL_DIGITS_INT + 1];

    printf ("MAX_DECIMAL_DIGITS_UCHAR     = %2zu\n",MAX_DECIMAL_DIGITS_UCHAR    );
    printf ("MAX_DECIMAL_DIGITS_USHORT    = %2zu\n",MAX_DECIMAL_DIGITS_USHORT   );
    printf ("MAX_DECIMAL_DIGITS_UINT      = %2zu\n",MAX_DECIMAL_DIGITS_UINT     );
    printf ("MAX_DECIMAL_DIGITS_ULONG     = %2zu\n",MAX_DECIMAL_DIGITS_ULONG    );
    printf ("MAX_DECIMAL_DIGITS_ULONGLONG = %2zu\n",MAX_DECIMAL_DIGITS_ULONGLONG);
    printf ("MAX_DECIMAL_DIGITS_UINT128   = %2zu\n",MAX_DECIMAL_DIGITS_UINT128  );

    printf ("MAX_DECIMAL_DIGITS_CHAR      = %2zu\n",MAX_DECIMAL_DIGITS_CHAR     );
    printf ("MAX_DECIMAL_DIGITS_SHORT     = %2zu\n",MAX_DECIMAL_DIGITS_SHORT    );
    printf ("MAX_DECIMAL_DIGITS_INT       = %2zu\n",MAX_DECIMAL_DIGITS_INT      );
    printf ("MAX_DECIMAL_DIGITS_LONG      = %2zu\n",MAX_DECIMAL_DIGITS_LONG     );
    printf ("MAX_DECIMAL_DIGITS_LONGLONG  = %2zu\n",MAX_DECIMAL_DIGITS_LONGLONG );
    printf ("MAX_DECIMAL_DIGITS_INT128    = %2zu\n",MAX_DECIMAL_DIGITS_INT128   );

    sprintf (IntegerString,"%d",INT_MAX);
    printf ("INT_MAX       = %d\n",INT_MAX);
    printf ("IntegerString = %s\n",IntegerString);

    sprintf (IntegerString,"%d",INT_MIN);
    printf ("INT_MIN       = %d\n",INT_MIN);
    printf ("IntegerString = %s\n",IntegerString);

    return EXIT_SUCCESS;
}
namespace details {
    template<typename T>
    constexpr size_t max_to_string_length_impl(T value) {
        return (value >= 0 && value < 10) ? 1                            // [0..9] -> 1
            : (std::is_signed<T>::value && value < 0 && value > -10) ? 2 // [-9..-1] -> 2
            : 1 + max_to_string_length_impl(value / 10);                 // ..-10] [10.. -> recursion
    }
}

template<typename T>
constexpr size_t max_to_string_length() { 
    return std::max(
        details::max_to_string_length_impl(std::numeric_limits<T>::max()),
        details::max_to_string_length_impl(std::numeric_limits<T>::min())); 
}