2008-11-28 每日WTF以下代码:
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; }
你会怎么写的?
如果你是一位经验丰富的C程序员,你会发现这段代码实际上并不那么糟糕.这是相对简单的(对于C),它的速度非常快.它有三个问题:
它在LONG_MIN(-2,147,483,648)的边缘情况下失败,因为否定这个数字会产生二进制补码
它假设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); }
说明:它在堆栈上创建一个本地缓冲区,然后以与初始代码相同的方法填充该缓冲区.然后,它将其复制到传递给函数的参数中,确保不会溢出缓冲区.它还有一个INT32_MIN的特例.如果原始缓冲区足够大,则返回值为0;如果缓冲区太小且返回结果字符串,则返回值为1.