如何修复我的 `itoa` 实现,使其不打印反向输出?
How do I fix my `itoa` implementation so it doesn't print reversed output?
我想在 C 中将一个整数转换成一串数字字符。
我试过使用 itoa
,但它不是标准的,我的 C 库也没有提供。
我尝试实现自己的 itoa
,但它无法正常工作:
#include <stdlib.h>
#include <stdio.h>
char *itoa(int val, char *buf, int base)
{
size_t ctr = 0;
for( ; val; val /= base )
{
buf[ctr++] = '0' + (val % base);
}
buf[ctr] = 0;
return buf;
}
int main(void)
{
unsigned char c = 201;
char *buf = malloc(sizeof(c)*8+1);
itoa(c, buf, 2);
puts(buf);
free(buf);
}
它给出反向输出。
例如,如果 c
是 'A'
并且 base
是 2
,则输出是这样的:0101101
我想要的输出是这样的:1011010
我该如何解决这个问题?
类似问题
我已经看过这个问题了:Is there a printf converter to print in binary format?
我不想 printf
格式说明符将整数打印为二进制,我想将二进制转换为字符串。
我已经看过这个问题了:Print an int in binary representation using C
尽管答案确实将整数转换为二进制数字串,但这是它唯一能做的事情。
限制
我希望 itoa
能够与其他 base
一起工作,例如 10
、8
等并正确打印(即 12345
转换为 "12345"
而不是 "11000000111001"
).
我不想使用 printf
或 sprintf
来执行此操作。
我不关心字符串的长度,只要结果正确即可。
我不想将整数转换为数字以外的 ASCII 字符,但 base
大于 10 的字符除外,在这种情况下,字符可能是字母数字。
答案必须完全符合这个原型:
char *itoa(int val, char *buf, int base);
可能有一个名为 nitoa
的函数具有此原型和 returns 保存 itoa
结果所需的字符数:
size_t nitoa(int val, int base);
这个解决方案适合我:
#include <errno.h>
#include <stdlib.h>
#include <string.h>
#define itoa lltoa
#define utoa ulltoa
#define ltoa lltoa
#define ultoa ulltoa
#define nitoa nlltoa
#define nutoa nulltoa
#define nltoa nlltoa
#define nultoa nulltoa
#define BASE_BIN 2
#define BASE_OCT 8
#define BASE_DEC 10
#define BASE_HEX 16
#define BASE_02Z 36
__extension__
char *ulltoa(unsigned long long val, char *buf, int base)
{
int remainder;
char c, *tmp = buf;
if(base < BASE_BIN)
{
errno = EINVAL;
return NULL;
}
do {
remainder = val % base;
if(remainder >= BASE_DEC) c = 'a' - BASE_DEC;
else c = '0';
*tmp++ = remainder + c;
val /= base;
} while(val);
*tmp = 0;
return strrev(buf);
}
__extension__
size_t nulltoa(unsigned long long val, int base)
{
size_t size = 0;
if(base < BASE_BIN)
{
errno = EINVAL;
return 0;
}
if(!val) size++;
for( ; val; val /= base, size++ );
return size;
}
__extension__
char *lltoa(long long val, char *buf, int base)
{
if(val < 0 && base > BASE_BIN)
{
val = -val;
*buf++ = '-';
}
return ulltoa(val, buf, base);
}
__extension__
size_t nlltoa(long long val, int base)
{
size_t size = 0;
if(val < 0 && base > BASE_BIN)
{
val = -val;
size++;
}
return size + nulltoa(val, base);
}
How do I fix my itoa
implementation so it doesn't print reversed output?
不要反转字符串,而是形成它 right-to-left。第 4 名,共
我推荐辅助函数也接收一个大小。
#include <limits.h>
char* itostr(char *dest, size_t size, int a, int base) {
// Max text needs occur with itostr(dest, size, INT_MIN, 2)
char buffer[sizeof a * CHAR_BIT + 1 + 1];
static const char digits[36] = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ";
if (base < 2 || base > 36) {
fprintf(stderr, "Invalid base");
return NULL;
}
// Start filling from the end
char* p = &buffer[sizeof buffer - 1];
*p = '[=10=]';
// Work with negative `int`
int an = a < 0 ? a : -a;
do {
*(--p) = digits[-(an % base)];
an /= base;
} while (an);
if (a < 0) {
*(--p) = '-';
}
size_t size_used = &buffer[sizeof(buffer)] - p;
if (size_used > size) {
fprintf(stderr, "Scant buffer %zu > %zu", size_used , size);
return NULL;
}
return memcpy(dest, p, size_used);
}
然后为了提供记忆,使用复合文字。
// compound literal C99 or later
#define INT_STR_SIZE (sizeof(int)*CHAR_BIT + 2)
#define MY_ITOA(x, base) itostr((char [INT_STR_SIZE]){""}, INT_STR_SIZE, (x), (base))
现在可以多次调用了。
int main(void) {
printf("%s %s %s %s\n", MY_ITOA(INT_MIN,10), MY_ITOA(-1,10), MY_ITOA(0,10), MY_ITOA(INT_MAX,10));
printf("%s %s\n", MY_ITOA(INT_MIN,2), MY_ITOA(INT_MIN,36));
return (0);
}
输出
-2147483648 -1 0 2147483647
-10000000000000000000000000000000 -ZIK0ZK
注意:sizeof(c)*8+1
对 INT_MIN
来说太小了,基数 2。
我想在 C 中将一个整数转换成一串数字字符。
我试过使用 itoa
,但它不是标准的,我的 C 库也没有提供。
我尝试实现自己的 itoa
,但它无法正常工作:
#include <stdlib.h>
#include <stdio.h>
char *itoa(int val, char *buf, int base)
{
size_t ctr = 0;
for( ; val; val /= base )
{
buf[ctr++] = '0' + (val % base);
}
buf[ctr] = 0;
return buf;
}
int main(void)
{
unsigned char c = 201;
char *buf = malloc(sizeof(c)*8+1);
itoa(c, buf, 2);
puts(buf);
free(buf);
}
它给出反向输出。
例如,如果 c
是 'A'
并且 base
是 2
,则输出是这样的:0101101
我想要的输出是这样的:1011010
我该如何解决这个问题?
类似问题
我已经看过这个问题了:Is there a printf converter to print in binary format?
我不想 printf
格式说明符将整数打印为二进制,我想将二进制转换为字符串。
我已经看过这个问题了:Print an int in binary representation using C
尽管答案确实将整数转换为二进制数字串,但这是它唯一能做的事情。
限制
我希望 itoa
能够与其他 base
一起工作,例如 10
、8
等并正确打印(即 12345
转换为 "12345"
而不是 "11000000111001"
).
我不想使用 printf
或 sprintf
来执行此操作。
我不关心字符串的长度,只要结果正确即可。
我不想将整数转换为数字以外的 ASCII 字符,但 base
大于 10 的字符除外,在这种情况下,字符可能是字母数字。
答案必须完全符合这个原型:
char *itoa(int val, char *buf, int base);
可能有一个名为 nitoa
的函数具有此原型和 returns 保存 itoa
结果所需的字符数:
size_t nitoa(int val, int base);
这个解决方案适合我:
#include <errno.h>
#include <stdlib.h>
#include <string.h>
#define itoa lltoa
#define utoa ulltoa
#define ltoa lltoa
#define ultoa ulltoa
#define nitoa nlltoa
#define nutoa nulltoa
#define nltoa nlltoa
#define nultoa nulltoa
#define BASE_BIN 2
#define BASE_OCT 8
#define BASE_DEC 10
#define BASE_HEX 16
#define BASE_02Z 36
__extension__
char *ulltoa(unsigned long long val, char *buf, int base)
{
int remainder;
char c, *tmp = buf;
if(base < BASE_BIN)
{
errno = EINVAL;
return NULL;
}
do {
remainder = val % base;
if(remainder >= BASE_DEC) c = 'a' - BASE_DEC;
else c = '0';
*tmp++ = remainder + c;
val /= base;
} while(val);
*tmp = 0;
return strrev(buf);
}
__extension__
size_t nulltoa(unsigned long long val, int base)
{
size_t size = 0;
if(base < BASE_BIN)
{
errno = EINVAL;
return 0;
}
if(!val) size++;
for( ; val; val /= base, size++ );
return size;
}
__extension__
char *lltoa(long long val, char *buf, int base)
{
if(val < 0 && base > BASE_BIN)
{
val = -val;
*buf++ = '-';
}
return ulltoa(val, buf, base);
}
__extension__
size_t nlltoa(long long val, int base)
{
size_t size = 0;
if(val < 0 && base > BASE_BIN)
{
val = -val;
size++;
}
return size + nulltoa(val, base);
}
How do I fix my
itoa
implementation so it doesn't print reversed output?
不要反转字符串,而是形成它 right-to-left。第 4 名,共
我推荐辅助函数也接收一个大小。
#include <limits.h>
char* itostr(char *dest, size_t size, int a, int base) {
// Max text needs occur with itostr(dest, size, INT_MIN, 2)
char buffer[sizeof a * CHAR_BIT + 1 + 1];
static const char digits[36] = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ";
if (base < 2 || base > 36) {
fprintf(stderr, "Invalid base");
return NULL;
}
// Start filling from the end
char* p = &buffer[sizeof buffer - 1];
*p = '[=10=]';
// Work with negative `int`
int an = a < 0 ? a : -a;
do {
*(--p) = digits[-(an % base)];
an /= base;
} while (an);
if (a < 0) {
*(--p) = '-';
}
size_t size_used = &buffer[sizeof(buffer)] - p;
if (size_used > size) {
fprintf(stderr, "Scant buffer %zu > %zu", size_used , size);
return NULL;
}
return memcpy(dest, p, size_used);
}
然后为了提供记忆,使用复合文字。
// compound literal C99 or later
#define INT_STR_SIZE (sizeof(int)*CHAR_BIT + 2)
#define MY_ITOA(x, base) itostr((char [INT_STR_SIZE]){""}, INT_STR_SIZE, (x), (base))
现在可以多次调用了。
int main(void) {
printf("%s %s %s %s\n", MY_ITOA(INT_MIN,10), MY_ITOA(-1,10), MY_ITOA(0,10), MY_ITOA(INT_MAX,10));
printf("%s %s\n", MY_ITOA(INT_MIN,2), MY_ITOA(INT_MIN,36));
return (0);
}
输出
-2147483648 -1 0 2147483647
-10000000000000000000000000000000 -ZIK0ZK
注意:sizeof(c)*8+1
对 INT_MIN
来说太小了,基数 2。