Если вы опытный программист на 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, если буфер был слишком мал, и результирующая строка была усечена.