「strtoll」については知っていますが、それは任意の基数 (2 から 36 の間) を 10 進数に変換しているため、10 進数を任意の基数基数に変換して反対のことを行う必要があります。
例は、10 進数 130 基数 12 = AA です。
次のコードは、一時バッファを使用して文字列を作成し、複製を返します。文字列は、最後から逆方向に作業し、別の文字列にインデックスを付けて各桁を設定することによって構築されます。これは、Java バージョンで短い文字列のコピーと追加を繰り返すよりもはるかに効率的です。返された文字列を使い終わったら解放し、基数が範囲外である可能性がある場合は NULL 戻りをチェックする必要があります...常に新しい文字列を割り当てることを避けるために、結果のために提供するバッファ。
/* return string representation of num in base rad as new string (or NULL) */
char *toBaseWhatever(int num, int rad)
{
char digits[] = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
int i;
char buf[66]; /* enough space for any 64-bit in base 2 */
/* bounds check for radix */
if (rad < 2 || rad > 62)
return NULL;
/* if num is zero */
if (!num)
return strdup("0");
/* null terminate buf, and set i at end */
buf[65] = '\0';
i = 65;
if (num > 0) { /* if positive... */
while (num) { /* until num is 0... */
/* go left 1 digit, divide by radix, and set digit to remainder */
buf[--i] = digits[num % rad];
num /= rad;
}
} else { /* same for negative, but negate the modulus and prefix a '-' */
while (num) {
buf[--i] = digits[-(num % rad)];
num /= rad;
}
buf[--i] = '-';
}
/* return a duplicate of the used portion of buf */
return strdup(buf + i);
}
自分で作成する必要がない場合は、'strtoll' または 'strtoull' が変換を行います。
long long i64 = 0x8000000000000000LL;
unsigned long long u64 = 0xFFFFFFFFFFFFFFFFULL;
printf("Signed long long: %lld\n", i64);
printf("Unsigned long long: %llu\n", u64);
printf("\n");
char buffer[30];
sprintf(buffer, "%lld", i64);
i64 = atoll(buffer);
i64 = strtoll(buffer, NULL, 10);
u64 = strtoull(buffer, NULL, 10);
[編集] この編集は、彼と @dmitri の解決策の間のタイミングに関する @willus のコメントに応えて (純粋に楽しみのために)、ミックスに 3 分の 1 を追加したものです。
純粋な速度という点では、Dmitri の製品は圧倒されますが、メモリ リークが含まれます。メモリが解放されないような方法で strdup() 関数を使用します。strdupa() は、割り当てられたメモリを解放する代替手段であり、ここでは適切な代替品になります。また、@Dmitri のコード (@willus が指摘したように) をまったく使用しない strdup()
またはstrdupa()
AnyRadixConvert関数のこの実装の功績です。
整数 0 から 5001 までの 3 つのそれぞれの結果は次のとおりです。
strdup()
これらの結果を生成したコードは次のとおりですStrDup()
。
#include "toolbox.h" //StrDup(), delete otherwise
#include <ansi_c.h>
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#define MAXLEN_127 127
void delaySome(void); //test the timers...
int AnyRadixConvert(const char* oldNumber, int oldRadix,
char* newNumber, int newRadix);
///Willus
static void willus_decimal_to_radix_base(char *s, int x,int base,int maxlen);
static void insert_char(char *s,int c,int maxlen);
static int digit(int x);
////Dmitri
char *dmitri_toBaseWhatever(int num, int rad);
int main(void)
{
char dataIn[66]="5001";
char dataOut[66];
int radixFrom = 10;
int radixTo = 2;
long long int i=0;
//support willus_decimal_to_radix_base
int x;
//support Dmitri
char demitri_result[66];
demitri_result[0]=0;
int dataInNum;
int maxInAll = 5001;
/*Converts from base x to base y*/ //values from 2 to 36 for either parameter
//time it
// Delay(1);
clock_t start, end;
long double elapsed1, elapsedWillus, elapsedDimitri;
start = clock();
//end time it
for(i=0;i<=maxInAll;i++)
{
sprintf(dataIn, "%lld", i);
AnyRadixConvert(dataIn,radixFrom,dataOut,radixTo);
}
//end timeit
end = clock();
elapsed1 = ((double) (end - start)) / CLOCKS_PER_SEC;
printf("AnyRadixConvert:\nFrom base %d: %s\nTo base %ld: %s\nElapsed time: %3.15Lf\n\n" ,radixFrom,dataIn,radixTo, dataOut, elapsed1);
//willus_decimal_to_radix_base
x=atol(dataIn);
dataOut[0]=0;
start = clock();
for(i=0;i<=maxInAll;i++)
{
willus_decimal_to_radix_base(dataOut,(int)i,radixTo,MAXLEN_127);
}
end = clock();
elapsedWillus = ((double) (end - start)) / CLOCKS_PER_SEC;
printf("willus_decimal_to_radix_base:\nFrom base %d: %s\nTo base %ld: %s\nElapsed time: %3.15Lf\n\n",radixFrom,dataIn,radixTo, dataOut, elapsedWillus);
//dimitri_toBaseWhatever
dataInNum = atol("123123132");
start = clock();
for(i=0;i<=maxInAll;i++)
{
strcpy(demitri_result, dmitri_toBaseWhatever((int)i, radixTo));
}
end = clock();
elapsedDimitri = ((double) (end - start)) / CLOCKS_PER_SEC;
printf("dimitri_toBaseWhatever:\nFrom base %d: %s\nTo base %ld: %s\nElapsed time: %3.15Lf\n\n" ,radixFrom,dataIn,radixTo, demitri_result, elapsedDimitri);
//////////////////////////
getchar();
return 0;
}
int AnyRadixConvert(const char* oldNumber, int oldRadix, char* newNumber, int newRadix)
{
long dataIn = 0L;
char digit = 0;
int i = 0;
int size=strlen(oldNumber);
char* reverseNew = NULL;
/*Checks if base if within bounds*/
if((oldRadix<=1 || oldRadix>36)||(newRadix<=1 || newRadix>36))
{
return 0;
}
/*Convert to base 10 from old base*/
for(i=0;i<size;i++)
{
if(oldNumber[i]>='0' && oldNumber[i]<='9')
{
dataIn+=(oldNumber[i]-'0')*pow(oldRadix,size-i-1);
}
else if(oldNumber[i]>='A' && oldNumber[i]<='Z')
{
dataIn+=(oldNumber[i]-'A' + 10)*pow(oldRadix,size-i-1);
}
else
{
return -1;
}
}
i=0;
/*Convert from base 10 to new base*/
while(dataIn>0)
{
digit = dataIn % newRadix;
(digit<10)?(newNumber[i] = digit + '0')
:(newNumber[i] = digit + 'A' -10);
dataIn=dataIn/newRadix;
i++;
}
newNumber[i]='\0';
/*Reverses newNumber*/
reverseNew = (char*)(malloc(sizeof(char)*strlen(newNumber)+1));
reverseNew[0]=0;
size = strlen(newNumber);
for(i=size-1; i>=0; i--)
{
reverseNew[i] = newNumber[size-1-i];
}
reverseNew[size]='\0';
strcpy(newNumber,reverseNew);
free(reverseNew);
return 1;
}
static void willus_decimal_to_radix_base(char *s, int x,int base,int maxlen)
{
int sign;
sign= (x<0) ? -1 : 1;
if (x<0)
x=-x;
s[0]='\0';
if (x==0)
{
if (maxlen > 0)
strcpy(s,"0");
return;
}
while (x>0)
{
int r;
r=x%base;
insert_char(s,digit(r),maxlen);
x /= base;
}
if (sign<0)
insert_char(s,'-',maxlen);
}
static void insert_char(char *s,int c,int maxlen)
{
int len;
len=strlen(s);
if (len>=maxlen)
memmove(&s[1],s,len-1);
else
memmove(&s[1],s,len+1);
s[0]=c;
}
static int digit(int x)
{
if (x<10)
return('0'+x);
return('A'+x-10);
}
////Dimitri
/* return string representation of num in base rad as new string (or NULL) */
char *dmitri_toBaseWhatever(int num, int rad)
{
char digits[] = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
int i;
char buf[66]; /* enough space for any 64-bit in base 2 */
buf[0]=0;
/* bounds check for radix */
if (rad < 2 || rad > 62)
return NULL;
/* if num is zero */
if (!num)
return StrDup("0");
//return strdup("0");
/* null terminate buf, and set i at end */
buf[65] = '\0';
i = 65;
if (num > 0) { /* if positive... */
while (num) { /* until num is 0... */
/* go left 1 digit, divide by radix, and set digit to remainder */
buf[--i] = digits[num % rad];
num /= rad;
}
} else { /* same for negative, but negate the modulus and prefix a '-' */
while (num) {
buf[--i] = digits[-(num % rad)];
num /= rad;
}
buf[--i] = '-';
}
/* return a duplicate of the used portion of buf */
return StrDup(buf + i);
//return strdup(buf + i);
}
void delaySome(void) //test the timer
{
time_t x = clock();
while ((clock() - x)<1000);
}