【问题标题】:Want to Convert Integer to String without itoa function想要在没有 itoa 函数的情况下将整数转换为字符串
【发布时间】:2012-04-03 13:53:42
【问题描述】:

我想在 C 中转换 int to char* 而不使用 itoa() 函数。

因为在我的 Linux 系统上我没有itoa 功能。我正在使用从here找到的这段代码

我想在同样使用 Linux 的嵌入式设备上运行此功能。

所以我正在寻找不使用itoa

我也不想使用sprintf,因为它仅用于打印。

所以请任何人帮我解决这个问题。

谢谢

【问题讨论】:

  • 我也不想使用 sprintf,因为它只用于打印这没有意义。
  • atoi 将毫无用处,因为它将ASCII 转换为整数,反之亦然。
  • @all 检查我更新的问题
  • 为什么说sprintf只用于打印?这不是真的。
  • @RoeeGavirel 他在评论之后写(编辑)了它。

标签: c linux embedded


【解决方案1】:

事情是snprintf 是完美的功能:

char str[LEN];
snprintf(str, sizeof(str), "%d", num);

【讨论】:

  • snprintf 用于避免溢出,否则是正确的建议 - 或者只是忽略我,因为我无法阅读,显然......
  • 我没有投反对票,但 stdio.h 通常被嵌入式系统禁止。例如,MISRA-C 从所有生产代码中禁止 stdio.h。类型安全性差和性能差是主要问题。而且由于程序员编写 itoa/atoi 函数非常容易,因此实际上没有必要仅将 stdio.h 用于此目的。
  • @Lundin 啊,我明白了。我想这是有道理的:-)
【解决方案2】:

这是一个你可以使用的简单的 sn-p。还有更优雅和更高级的方法,但这可以完成工作。

在过去的嵌入式项目中,我测量它的效率大约是 sprintf() 的 1000 倍。此代码也符合 MISRA-C。

void getDecStr (uint8_t* str, uint8_t len, uint32_t val)
{
  uint8_t i;

  for(i=1; i<=len; i++)
  {
    str[len-i] = (uint8_t) ((val % 10UL) + '0');
    val/=10;
  }

  str[i-1] = '\0';
}

【讨论】:

  • 我认为您需要在此例程中使用一些明亮的红色闪烁警告标志。首先,如果缓冲区大于绝对必要,它将用前导零填充返回的字符串。其次,它不处理负数;授予,您将其声明为无符号,但 OP 要求 itoa() 类似工作,这意味着有符号整数。我认为“第三”不是基数参数,但考虑到 OP 作为答案发布的i_to_a() 实现,我猜 MS itoa() 接口的一部分对他来说并不重要。
  • @WarrenYoung 这故意保持简单,可以对其进行修改以获得更多功能。此函数是为实时嵌入式系统编写的,因此其中不包含不需要的功能。前导零是为了使其具有确定性。
  • 老实说,我只是想证明自己编写这样的代码是多么容易。然而,如此多的准程序员不断地要求 atoi/itoa...与其要求鱼,不如学习如何自己钓到鱼。如果您从事渔民工作,这一点尤其重要。
  • 填充仍然是一个陷阱。如果你传递一个 100 个字符的缓冲区,它最终花费的时间大约是我在这里测试过的最慢的其他方法的 3.5 倍。如果将缓冲区大小减少到 10,它的速度大约是最快速度的两倍。它表明如果您知道输入数据的确切特征,您可以为速度而编写代码,但我不建议将其作为通用函数,没有警告。
  • @WarrenYoung 为什么会有人将超过 11 个字符的缓冲区传递给函数? ULONG_MAX = 4294967295。10 位数字 + 1 个空项作为最坏情况。此外,在这种情况下,“len”是函数应该分发的位数,不是缓冲区大小。
【解决方案3】:
#include <stdio.h>
#include <string.h>

#if 0
char *strrev(char *str){
    char c, *front, *back;

    if(!str || !*str)
        return str;
    for(front=str,back=str+strlen(str)-1;front < back;front++,back--){
        c=*front;*front=*back;*back=c;
    }
    return str;
}
#endif

char *itoa(int v, char *buff, int radix_base){
    static char table[] = "0123456789abcdefghijklmnopqrstuvwxyz";
    char *p=buff;
    unsigned int n = (v < 0 && radix_base == 10)? -v : (unsigned int) v;
    while(n>=radix_base){
        *p++=table[n%radix_base];
        n/=radix_base;
    }
    *p++=table[n];
    if(v < 0 && radix_base == 10) *p++='-';
    *p='\0';
    return strrev(buff);
}

int main ()
{
  int i;
  char str[33];

  printf ("Enter a number: ");
  scanf ("%d",&i);

  itoa (i,str,10);
  printf ("decimal: %s\n", str);

  itoa (i, str, 16);
  printf ("hexadecimal: %s\n", str);

  itoa (i, str, 2);
  printf ("binary: %s\n", str);

  return 0;
}

【讨论】:

  • 这是迄今为止发布的选项中最慢的。在我的测试系统上使用我的测试数据集,snprintf() 花费了 17.1 秒,i_to_a()malloc() 和相关的所需 free() 花费了 18.7 秒,i_to_a() 修改为采用预分配缓冲区花费了 15.2 秒,而您的 @ 987654327@ 花了 20.5 秒。修改您的itoa() 以添加负数支持,并将基数增加到 36 以使其与 MS 实现兼容,将其略微提高到 20.7 秒。不过,+1 表示有趣。 :)
  • 1.负数:int n -> int v, unsigned int n = v. 2.radices 2-36:"0123456789abcdef" -> "012...xyz"。 3.为什么慢:使用/%。例如替换 Montgomery_reduction。但是它对日常使用的速度要求不高吗?
  • 我也不必否定我的观点。但暂时尝试修复。
  • 谢谢,我现在感觉好多了。 :) 在我自己的版本中,我并没有将负数限制为仅以 10 为底,但我看到 MS 就是这样做的。我想他们试图允许设置高位的值的 hex/bin/oct 输出而不让它们显示为负数。他们应该定义uitoa()。哦,好吧。
  • 是的,MS itoa 是理解的,所以只在以10为底的时候放一个减号。但是,这并不意味着要限制负输入。
【解决方案4】:

我找到了关于这个的解决方案..

我很高兴,我想要我所期望的。

#include <string.h>
#include <stdlib.h>

char *i_to_a(int num);

int main()
{

    char *str = i_to_a(4567);
    printf("%s",str);
    free(str);
    str = NULL;
return 0;

}
int no_of_digits(int num)
{
    int digit_count = 0;

    while(num > 0)
    {
        digit_count++;
        num /= 10;
    }

    return digit_count;
}


char *i_to_a(int num)
{
    char *str;
    int digit_count = 0;

    if(num < 0)
    {
        num = -1*num;
        digit_count++;
    }

    digit_count += no_of_digits(num);   
    str = malloc(sizeof(char)*(digit_count+1));

    str[digit_count] = '\0';

    while(num > 0)
    {
        str[digit_count-1] = num%10 + '0';
        num = num/10;
        digit_count--;
    }

    if(digit_count == 1)
        str[0] = '-';

    return str;
}

【讨论】:

  • 请记住,这段代码会泄漏内存。此外,-1 用于教授在 C 中对 malloc 的结果进行类型转换。阅读 thisthis。删除类型转换,我将删除反对票。
  • @Lundin:是的,main() 应该释放缓冲区,但恕我直言,i_to_a() 首先不应该分配缓冲区。没有充分的理由不应该采用预先分配的缓冲区。分配和返回缓冲区的实用函数在我的书中是一种代码味道。既然他已经离开了 MSitoa() 接口,他还不如添加一个长度参数,并检查缓冲区溢出。
  • @WarrenYoung 我完全同意你所说的一切。
  • 还需要检查malloc是否成功。 if(str!=NULL) {printf("Malloc 失败\n"); /* 清理 */ return;}
  • i_to_a(0) 失败。 i_to_a(INT_MIN) 失败。
猜你喜欢
  • 1970-01-01
  • 2012-08-02
  • 2011-07-31
  • 2014-12-28
  • 1970-01-01
  • 2012-05-12
  • 1970-01-01
  • 2011-04-28
  • 2010-09-18
相关资源
最近更新 更多