Одним из отсутствующих атрибутов этого «Преобразовать длинное целое число в строку base 36» является string management.
Приведенное ниже значение страдает от потенциального переполнения буфера, когда destination
слишком мало .
char *long_to_string(char *destination, long num, int base);
(Предполагается, что 32-битная длина) Рассмотрим переполнение ниже, поскольку результирующая строка должна быть "-10000000000000000000000000000000", для кодировки которой требуется 34 байта.
char buffer[33]; // Too small
long_to_string(buffer, LONG_MIN, 2); // Oops!
Альтернатива передаст размер буфера и затем предоставит некоторую сигнализацию об ошибках, когда буфер слишком мал.
char* longtostr(char *dest, size_t size, long a, int base)
Начиная с C99, вместо кода может использовать составной литерал для предоставления необходимого пространства - без вызова кода, который пытается вычислить необходимый размер или явно выделить буфер.
Возвращенный указатель строки из TO_BASE(long x, int base)
действителен до конца блока.
#include <assert.h>
#include <limits.h>
#define TO_BASE_N (sizeof(long)*CHAR_BIT + 2)
// v. compound literal .v
#define TO_BASE(x, b) my_to_base((char [TO_BASE_N]){""}, (x), (b))
char *my_to_base(char *buf, long a, int base) {
assert(base >= 2 && base <= 36);
long i = a < 0 ? a : -a; // use the negative side - this handle _MIN, _MAX nicely
char *s = &buf[TO_BASE_N - 1];
*s = '\0';
do {
s--;
*s = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"[-(i % base)];
i /= base;
} while (i);
if (a < 0) {
s--;
*s = '-';
}
// Could add memmove here to move the used buffer to the beginning
return s;
}
#include <limits.h>
#include <stdio.h>
int main(void) {
long ip1 = 0x01020304;
long ip2 = 0x05060708;
long ip3 = LONG_MIN;
printf("%s %s\n", TO_BASE(ip1, 16), TO_BASE(ip2, 16), TO_BASE(ip3, 16));
printf("%s %s\n", TO_BASE(ip1, 2), TO_BASE(ip2, 2), TO_BASE(ip3, 2));
puts(TO_BASE(ip1, 8));
puts(TO_BASE(ip1, 36));
puts(TO_BASE(ip3, 10));
}