C编程 - 整数/长到字符串表示

时间:2016-07-16 08:30:58

标签: c arrays printf long-integer

我只是阅读" C接口和实现"。书中描述了一些非常有趣的概念。有时(在我看来)代码非常难看,但现在我有一个关于将整数/ long转换为字符串(char数组)的问题。书中描述的是:

const char *Atom_int(long n) {
    char str[43];
    char *s = str + sizeof str;
    unsigned long m;
    if (n == LONG_MIN)
        m = LONG_MAX + 1UL;
    else if (n < 0)
        m = -n;
    else
        m = n;
    do
        *--s = m%10 + '0';
    while ((m /= 10) > 0);
    if (n < 0)
        *--s = '-';

    return Atom_new(s, str + sizeof str - s);
}

由于没有描述为什么使用这个功能的方式......我想知道为什么它不仅仅是简单的东西:

const char *Atom_int(long n)
{
    char str[43];
    char *s = str;
    sprintf(str, "%ld", n);

    return Atom_new(s, str + sizeof str - s);
}

有什么区别吗?我错过了关于我的&#34;简单&#34;使用sprintf的方法可能会导致与书中的函数不同的结果?我的意思是,如果它只是为了展示如何将长片转换为不使用ltoa / sprintf / ...的字符串,那很好。但如果这是唯一的原因,这是不必要的复杂,......

1 个答案:

答案 0 :(得分:6)

您为两个功能发布的原始代码存在两个主要问题:

  • str数组未'\0'终止,在传递给printf时调用未定义的行为。
  • 将指针s返回到具有自动存储str的数组也是不正确的。取消引用此返回值也将调用未定义的行为。

关于你的问题,第一个函数的目的是显示整数到字符串转换器的实现。使用sprintf会失败。请注意作者如何处理INT_MIN的子区域情况:计算-n会因为大多数系统上的整数溢出而调用未定义的行为,尽管结果在所有现代系统上都是正确的。但完全符合标准是一项困难的艺术:他的解决方案假设2s补充,否则将失败。

这是一个使用相同原型的改进解决方案。它更具可移植性,不需要特殊情况LONG_MIN,可以减少分割和模运算。

const char *Atom_int(long n) {
    char str[43];
    char *s = str + sizeof str;
    unsigned long m;
    if (n < 0)
        m = (unsigned long)-(n + 1) + 1;
    else
        m = n;

    while (m >= 10) {
        *--s = m % 10 + '0';
        m /= 10;
    }
    *--s = m + '0';
    if (n < 0)
        *--s = '-';

    return Atom_new(s, str + sizeof str - s);
}

另请注意,您建议的替代方案不正确:您将错误的长度传递给Atom_new()。您应该传递sprintfsnprintf返回的字节数。这是一个改进版本:

const char *Atom_int(long n) {
    char str[43];
    return Atom_new(str, snprintf(str, sizeof str, "%ld", n));
}