摘要:
将整数按指定进位做转换
代码实现:
原始的拙劣的实现:
#include <string.h>
#include <stdint.h>
#include <stdio.h>
#include <string>
#include <cstring>
#include <iostream>
#include <memory>
typedef unsigned long long int ulonglong; /* ulong or unsigned long long */
typedef long long int longlong;
typedef longlong int64;
typedef ulonglong uint64;
extern char *llstr(longlong value,char *buff);
extern char *ullstr(longlong value,char *buff);
extern char *int2str(long val, char *dst, int radix, int upcase);
extern char *int10_to_str(long val,char *dst,int radix);
extern char *str2int(const char *src,int radix,long lower,long upper,
long *val);
longlong my_strtoll10(const char *nptr, char **endptr, int *error);
#if SIZEOF_LONG == SIZEOF_LONG_LONG
#define ll2str(A,B,C,D) int2str((A),(B),(C),(D))
#define longlong10_to_str(A,B,C) int10_to_str((A),(B),(C))
#undef strtoll
#define strtoll(A,B,C) strtol((A),(B),(C))
#define strtoull(A,B,C) strtoul((A),(B),(C))
#else
extern char *ll2str(longlong val,char *dst,int radix, int upcase);
extern char *longlong10_to_str(longlong val,char *dst,int radix);
#endif
#define longlong2str(A,B,C) ll2str((A),(B),(C),1)
#define NullS (char *) 0
typedef unsigned char uchar; /* Short for unsigned char */
char _dig_vec_upper[] =
"0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ";
char _dig_vec_lower[] =
"0123456789abcdefghijklmnopqrstuvwxyz";
char *
int2str(long int val, char *dst, int radix,
int upcase)
{
char buffer[65];
char *p;
long int new_val;
char *dig_vec= upcase ? _dig_vec_upper : _dig_vec_lower;
ulong uval= (ulong) val;
if (radix < 0)
{
if (radix < -36 || radix > -2)
return NullS;
if (val < 0)
{
*dst++ = '-';
/* Avoid integer overflow in (-val) for LLONG_MIN (BUG#31799). */
uval = (ulong)0 - uval;
}
radix = -radix;
}
else if (radix > 36 || radix < 2)
return NullS;
/*
The slightly contorted code which follows is due to the fact that
few machines directly support unsigned long / and %. Certainly
the VAX C compiler generates a subroutine call. In the interests
of efficiency (hollow laugh) I let this happen for the first digit
only; after that "val" will be in range so that signed integer
division will do. Sorry 'bout that. CHECK THE CODE PRODUCED BY
YOUR C COMPILER. The first % and / should be unsigned, the second
% and / signed, but C compilers tend to be extraordinarily
sensitive to minor details of style. This works on a VAX, that's
all I claim for it.
*/
p = &buffer[sizeof(buffer)-1];
*p = '\0';
new_val= uval / (ulong) radix;
*--p = dig_vec[(uchar) (uval- (ulong) new_val*(ulong) radix)];
val = new_val;
while (val != 0)
{
ldiv_t res;
res=ldiv(val,radix);
*--p = dig_vec[res.rem];
val= res.quot;
}
while ((*dst++ = *p++) != 0) ;
return dst-1;
}
static char *Text(int64_t value_, char buf[], int scale) {
bool sign = true;
if (value_ < 0) {
sign = false;
value_ *= -1;
}
longlong2str(value_, buf, 10);
int l = (int)std::strlen(buf);
std::memset(buf + l + 1, ' ', 21 - l);
int pos = 21;
int i = 0;
for (i = l; i >= 0; i--) {
if (scale != 0 && pos + scale == 20) {
buf[pos--] = '.';
i++;
} else {
buf[pos--] = buf[i];
buf[i] = ' ';
}
}
if (scale >= l) {
buf[20 - scale] = '.';
buf[20 - scale - 1] = '0';
i = 20 - scale + 1;
while (buf[i] == ' ') buf[i++] = '0';
}
pos = 0;
while (buf[pos] == ' ') pos++;
if (!sign) buf[--pos] = '-';
return buf + pos;
}
int main()
{
int64_t value = -12345;
char buf[1024] = {0};
int scale = 3;
Text(value, buf, scale);
printf("buf: %s\n", buf);
return 0;
}
优化后的实现:
#include <string.h>
#include <stdint.h>
#include <stdio.h>
#include <string>
#include <cstring>
#include <iostream>
#include <memory>
typedef unsigned long long int ulonglong; /* ulong or unsigned long long */
typedef long long int longlong;
typedef longlong int64;
typedef ulonglong uint64;
extern char *llstr(longlong value,char *buff);
extern char *ullstr(longlong value,char *buff);
#define NullS (char *) 0
typedef unsigned char uchar; /* Short for unsigned char */
static char *Text(int64_t value_, char buf[], int scale) {
bool sign = value_ >= 0;
int index = 0;
int left_dec = 0;
if (!sign) {
buf[index++] = '-';
++left_dec;
value_ = - value_;
}
int64_t value_div = value_;
int loc = 0;
while (value_div) {
++loc;
value_div /= 10;
}
if (scale > loc) {
return NULL;
}
left_dec += loc - scale;
value_div = value_;
while (value_div) {
int pos = index + loc - 1;
if (pos >= left_dec) {
++pos;
}
buf[pos] = (value_div % 10) + '0';
if (pos == (left_dec+1)) {
--pos;
buf[pos] = '.';
}
value_div /= 10;
--loc;
}
return buf;
}
int main()
{
int64_t value = -12345;
char buf[1024] = {0};
int scale = 3;
Text(value, buf, scale);
printf("buf: %s\n", buf);
return 0;
}