Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/c/55.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
C 您将如何在每日WTF中实现柱状功能?_C_Coding Style - Fatal编程技术网

C 您将如何在每日WTF中实现柱状功能?

C 您将如何在每日WTF中实现柱状功能?,c,coding-style,C,Coding Style,对于2008-11-28柱,以下代码: static char *nice_num(long n) { int neg = 0, d = 3; char *buffer = prtbuf; int bufsize = 20; if (n < 0) { neg = 1; n = -n; } buffer += bufsize; *--buffer = '\0'; do {

对于2008-11-28柱,以下代码:

static char *nice_num(long n)
{
    int neg = 0, d = 3;
    char *buffer = prtbuf;
    int bufsize = 20;

    if (n < 0)
    {
        neg = 1;
        n = -n;
    }
    buffer += bufsize;
    *--buffer = '\0';

    do
    {
        *--buffer = '0' + (n % 10);
        n /= 10;
        if (--d == 0)
        {
            d = 3;
            *--buffer = ',';
        }
    }
    while (n);

    if (*buffer == ',') ++buffer;
    if (neg) *--buffer = '-';
    return buffer;
}
static char*nice_num(长n)
{
int-neg=0,d=3;
char*buffer=prtbuf;
int bufsize=20;
if(n<0)
{
负=1;
n=-n;
}
缓冲区+=bufsize;
*--缓冲区='\0';
做
{
*--缓冲区='0'+(n%10);
n/=10;
如果(--d==0)
{
d=3;
*--缓冲区=',';
}
}
而(n);
如果(*buffer==',')++buffer;
如果(负)*--buffer='-';
返回缓冲区;
}

您将如何编写它?

如果您是一名经验丰富的C程序员,您会意识到这段代码实际上并没有那么糟糕。它相对简单(对于C),而且速度非常快。它有三个问题:

static int nice_num(char *buffer, size_t len, int32_t n)
{
  int neg = 0, d = 3;
  char buf[16];
  size_t bufsize = sizeof(buf);
  char *pbuf = buf + bufsize;

  if(n < 0)
  {
    if(n == INT32_MIN)
    {
      strncpy(buffer, "-2,147,483,648", len);
      return len <= 14;
    }

    neg = 1;
    n = -n;
  }

  *--pbuf = '\0';

  do
  {
    *--pbuf = '0' + (n % 10);
    n /= 10;
    if(--d == 0)
    {
      d = 3;
      *--pbuf = ',';
    }
  }
  while(n > 0);

  if(*pbuf == ',') ++pbuf;
  if(neg) *--pbuf = '-';

  strncpy(buffer, pbuf, len);
  return len <= strlen(pbuf);
}
  • 它在LONG_MIN(-2147483648)的边缘情况下失败,因为对这个数字求反会产生两个补码
    • 它假设32位整数-对于64位长,20字节的缓冲区不够大
    • 它不是线程安全的-它使用全局静态缓冲区,因此多个线程同时调用它将导致争用情况
  • 问题#1很容易通过特殊情况解决。为了解决#2,我将代码分为两个函数,一个用于32位整数,另一个用于64位整数#3是有点难-我们必须改变接口,使完全线程安全

    以下是我的解决方案,基于此代码,但经过修改以解决这些问题:

    static int nice_num(char *buffer, size_t len, int32_t n)
    {
      int neg = 0, d = 3;
      char buf[16];
      size_t bufsize = sizeof(buf);
      char *pbuf = buf + bufsize;
    
      if(n < 0)
      {
        if(n == INT32_MIN)
        {
          strncpy(buffer, "-2,147,483,648", len);
          return len <= 14;
        }
    
        neg = 1;
        n = -n;
      }
    
      *--pbuf = '\0';
    
      do
      {
        *--pbuf = '0' + (n % 10);
        n /= 10;
        if(--d == 0)
        {
          d = 3;
          *--pbuf = ',';
        }
      }
      while(n > 0);
    
      if(*pbuf == ',') ++pbuf;
      if(neg) *--pbuf = '-';
    
      strncpy(buffer, pbuf, len);
      return len <= strlen(pbuf);
    }
    
    static int nice_num(字符*缓冲区,大小长度,整数32)
    {
    int-neg=0,d=3;
    char-buf[16];
    尺寸=尺寸(buf);
    char*pbuf=buf+bufsize;
    if(n<0)
    {
    如果(n==INT32_MIN)
    {
    strncpy(缓冲区“-2147483648”,len);
    返回长度(0);
    如果(*pbuf==',')+pbuf;
    如果(负)*--pbuf='-';
    strncpy(缓冲区、pbuf、len);
    纯C中的返回长度:

    #include <stdio.h>
    #include <limits.h>
    
    static char *prettyNumber(long num, int base, char separator)
    {
    #define bufferSize      (sizeof(long) * CHAR_BIT)
            static char buffer[bufferSize + 1];
            unsigned int pos = 0;
    
            /* We're walking backwards because numbers are right to left. */
            char *p = buffer + bufferSize;
            *p = '\0';
    
            int negative = num < 0;
    
            do
            {
                    char digit = num % base;
                    digit += '0';
    
                    *(--p) = digit;
                    ++pos;
    
                    num /= base;
    
                    /* This the last of a digit group? */
                    if(pos % 3 == 0)
                    {
    /* TODO Make this a user setting. */
    #ifndef IM_AMERICAN
    #       define IM_AMERICAN_BOOL 0
    #else
    #       define IM_AMERICAN_BOOL 1
    #endif
                            /* Handle special thousands case. */
                            if(!IM_AMERICAN_BOOL && pos == 3 && num < base)
                            {
                                    /* DO NOTHING */
                            }
                            else
                            {
                                    *(--p) = separator;
                            }
                    }
            } while(num);
    
            if(negative)
                    *(--p) = '-';
    
            return p;
    #undef bufferSize
    }
    
    int main(int argc, char **argv)
    {
            while(argc > 1)
            {
                    long num = 0;
    
                    if(sscanf(argv[1], "%ld", &num) != 1)
                            continue;
    
                    printf("%ld = %s\n", num, prettyNumber(num, 10, ' '));
    
                    --argc;
                    ++argv;
            };
    
            return 0;
    }
    
    #包括
    #包括
    静态字符*prettyNumber(长数字、整数基、字符分隔符)
    {
    #定义缓冲区大小(sizeof(long)*字符位)
    静态字符缓冲区[bufferSize+1];
    无符号整数pos=0;
    /*我们在倒退,因为数字是从右到左的*/
    char*p=缓冲区+缓冲区大小;
    *p='\0';
    int负=num<0;
    做
    {
    字符位数=基数的num%;
    数字+='0';
    *(-p)=数字;
    ++pos;
    num/=基数;
    /*这是数字组的最后一个吗*/
    如果(位置%3==0)
    {
    /*TODO将此设置为用户设置*/
    #我是美国人
    #定义我是美国人吗
    #否则
    #定义我是美国人
    #恩迪夫
    /*处理特殊情况*/
    如果(!IM_AMERICAN_BOOL&&pos==3&&num1)
    {
    long num=0;
    如果(sscanf(argv[1]、%ld”、&num)!=1)
    继续;
    printf(“%ld=%s\n”,num,prettyNumber(num,10,);
    --argc;
    ++argv;
    };
    返回0;
    }
    

    通常情况下,我会返回一个分配的缓冲区,用户需要释放缓冲区。这个添加很简单。

    这可能与我实际编写缓冲区的方式非常接近。我能立即看出解决方案的唯一错误是,在LONG_MIN为-(LONG_MAX+1)的机器上,LONG_MIN不起作用,这是当今大多数机器。我可能会使用
    localeconv
    来获取千位分隔符,而不是使用逗号,并且我可能会更仔细地计算缓冲区大小,但对我来说,算法和实现似乎非常简单,并不是C的WTF(C++有更好的解决方案).

    嗯……我想我不应该承认这一点,但我的嵌入式系统int-to-string例程的工作方式几乎完全相同(但没有添加逗号)

    这并不是特别简单,但如果您在一个无法使用
    snprintf()
    的系统上工作,我不会称之为WTF

    写上述内容的人可能注意到
    printf()
    例程家族不能进行逗号分组,所以他提出了自己的方法

    脚注:有些库的
    printf()
    样式格式确实支持分组,但它们不是标准格式。我知道发布的代码不支持使用“.”进行分组的其他区域设置。但这不是WTF,可能只是一个bug。

    Lisp:

    (defun pretty-number (x) (format t "~:D" x))
    

    我很惊讶我能如此轻松地做到这一点。我甚至还没有读完我的Lisp书的第一章。xD(或者应该说,~:D)

    我感到厌烦,并用Perl.Works实现了这个幼稚的实现

    
    sub pretify {
        my $num = $_[0];
        my $numstring = sprintf( "%f", $num );
    
        # Split into whole/decimal
        my ( $whole, $decimal ) = ( $numstring =~ /(^\d*)(.\d+)?/ );
        my @chunks;
        my $output = '';
    
        # Pad whole into multiples of 3
        $whole = q{ } x ( 3 - ( length $whole ) % 3 ) . $whole;
    
        # Create an array of all 3 parts.
        @chunks = $whole =~ /(.{3})/g;
    
        # Reassemble with commas
        $output = join ',', @chunks;
        if ($decimal) {
            $output .= $decimal;
        }
    
        # Strip Padding ( and spurious commas )
        $output =~ s/^[ ,]+//;
    
        # Strip excess tailing zeros
        $output =~ s/0+$//;
    
        # Ending with . is ugly
        $output =~ s/\.$//;
        return $output;
    }
    
    print "\n", pretify 100000000000000000000000000.0000;
    print "\n", pretify 10_202_030.45;
    print "\n", pretify 10_101;
    print "\n", pretify 0;
    print "\n", pretify 0.1;
    print "\n", pretify 0.0001;
    print "\n";
    
    size\t
    签名作为文本分组在1000的幂上(字符*s,最大值,整数n)
    {
    
    如果(max)当我读到你的第一段时,我决定实际尝试阅读代码。令我惊讶的是,我很容易理解它是如何工作的。我希望这是一件好事。=]我对这段代码唯一的不满是strncpy()如果要复制的字符串比接收它的缓冲区长,则不保证空终止。返回值会发出信号,但通常最好确保输出以空终止。缺少:
    static\u assert(INT\u MIN==-2147483648)
    。在代码中混合使用神奇字符串和符号常量只是一个等待发生的意外。我注意到,每日WTF网站上的评论似乎大多指出,这是不可能的