将长整数(十进制)转换为 base 36 字符串(C 中的 strtol 倒函数)
Convert long integer(decimal) to base 36 string (strtol inverted function in C)
我可以使用 strtol
函数将基于 base36 的值(保存为字符串)转换为 long int
:
long int val = strtol("ABCZX123", 0, 36);
是否有标准函数允许将其反转?即把一个long int
val变量转成base36字符串,再得到"ABCZX123"
?
没有这方面的标准功能。你需要自己写一个。
用法示例:https://godbolt.org/z/MhRcNA
const char digits[] = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
char *reverse(char *str)
{
char *end = str;
char *start = str;
if(!str || !*str) return str;
while(*(end + 1)) end++;
while(end > start)
{
int ch = *end;
*end-- = *start;
*start++ = ch;
}
return str;
}
char *tostring(char *buff, long long num, int base)
{
int sign = num < 0;
char *savedbuff = buff;
if(base < 2 || base >= sizeof(digits)) return NULL;
if(buff)
{
do
{
*buff++ = digits[abs(num % base)];
num /= base;
}while(num);
if(sign)
{
*buff++ = '-';
}
*buff = 0;
reverse(savedbuff);
}
return savedbuff;
}
这是另一个不需要字符源数组的选项,但可移植性较差,因为并非所有字符编码都具有连续的字母字符,例如 EBCDIC。测试 HERE
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <stdbool.h>
#include <limits.h>
char get_chars(long long value)
{
if (value >= 0 && value <= 9)
return value + '0';
else
return value - 10 + 'A';
}
void reverse_string(char *str)
{
int len = strlen(str);
for (int i = 0; i < len/2; i++)
{
char temp = str[i];
str[i] = str[len - i - 1];
str[len - i - 1] = temp;
}
}
char* convert_to_base(char *res, int base, long long input)
{
bool flag = 0;
int index = 0;
if(input < 0){
input = llabs(input);
flag = 1;
}
else if(input == 0){
res[index++] = '0';
res[index] = '[=10=]';
return res;
}
while(input > 0)
{
res[index++] = get_chars(input % base);
input /= base;
}
if(flag){
res[index++] = '-';
}
res[index] = '[=10=]';
reverse_string(res);
return res;
}
int main() {
long long input = 0;
printf("** Integer to Base-36 **\n ");
printf("Enter a valid number: ");
scanf("%lld", &input);
if(input >= LLONG_MAX && input <= LLONG_MIN){
printf("Invalid number");
return 0;
}
int base = 36;
char res[100];
printf("%lld -> %s\n", input, convert_to_base(res, base, input));
return 0;
}
此 "Convert long integer to base 36 string" 缺少的属性之一是 string 管理。
当 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 开始,代码可以使用 复合文字 来提供所需的 space - 无需调用代码尝试计算所需的大小,也无需显式分配缓冲区。
从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 = '[=13=]';
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));
}
我可以使用 strtol
函数将基于 base36 的值(保存为字符串)转换为 long int
:
long int val = strtol("ABCZX123", 0, 36);
是否有标准函数允许将其反转?即把一个long int
val变量转成base36字符串,再得到"ABCZX123"
?
没有这方面的标准功能。你需要自己写一个。
用法示例:https://godbolt.org/z/MhRcNA
const char digits[] = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
char *reverse(char *str)
{
char *end = str;
char *start = str;
if(!str || !*str) return str;
while(*(end + 1)) end++;
while(end > start)
{
int ch = *end;
*end-- = *start;
*start++ = ch;
}
return str;
}
char *tostring(char *buff, long long num, int base)
{
int sign = num < 0;
char *savedbuff = buff;
if(base < 2 || base >= sizeof(digits)) return NULL;
if(buff)
{
do
{
*buff++ = digits[abs(num % base)];
num /= base;
}while(num);
if(sign)
{
*buff++ = '-';
}
*buff = 0;
reverse(savedbuff);
}
return savedbuff;
}
这是另一个不需要字符源数组的选项,但可移植性较差,因为并非所有字符编码都具有连续的字母字符,例如 EBCDIC。测试 HERE
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <stdbool.h>
#include <limits.h>
char get_chars(long long value)
{
if (value >= 0 && value <= 9)
return value + '0';
else
return value - 10 + 'A';
}
void reverse_string(char *str)
{
int len = strlen(str);
for (int i = 0; i < len/2; i++)
{
char temp = str[i];
str[i] = str[len - i - 1];
str[len - i - 1] = temp;
}
}
char* convert_to_base(char *res, int base, long long input)
{
bool flag = 0;
int index = 0;
if(input < 0){
input = llabs(input);
flag = 1;
}
else if(input == 0){
res[index++] = '0';
res[index] = '[=10=]';
return res;
}
while(input > 0)
{
res[index++] = get_chars(input % base);
input /= base;
}
if(flag){
res[index++] = '-';
}
res[index] = '[=10=]';
reverse_string(res);
return res;
}
int main() {
long long input = 0;
printf("** Integer to Base-36 **\n ");
printf("Enter a valid number: ");
scanf("%lld", &input);
if(input >= LLONG_MAX && input <= LLONG_MIN){
printf("Invalid number");
return 0;
}
int base = 36;
char res[100];
printf("%lld -> %s\n", input, convert_to_base(res, base, input));
return 0;
}
此 "Convert long integer to base 36 string" 缺少的属性之一是 string 管理。
当 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 开始,代码可以使用 复合文字 来提供所需的 space - 无需调用代码尝试计算所需的大小,也无需显式分配缓冲区。
从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 = '[=13=]';
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));
}