C 您将如何在每日WTF中实现柱状功能?
对于2008-11-28柱,以下代码: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 {
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);
}
- 它假设32位整数-对于64位长,20字节的缓冲区不够大
- 它不是线程安全的-它使用全局静态缓冲区,因此多个线程同时调用它将导致争用情况
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&&num 1)
{
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网站上的评论似乎大多指出,这是不可能的