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

inz*_*nez -4 c arrays printf long-integer

我只是在阅读"C接口和实现".书中描述了一些非常有趣的概念.有时(在我看来)代码非常难看,但现在我有一个关于将整数/长转换为字符串(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);
}
Run Code Online (Sandbox Code Playgroud)

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

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

    return Atom_new(s, str + sizeof str - s);
}
Run Code Online (Sandbox Code Playgroud)

有什么区别吗?我错过了任何关于使用sprintf的"简单"方法的东西,它可能导致与书中的功能不同的结果?我的意思是,如果仅仅是为了展示如何将长片转换为不使用ltoa/sprintf/...的字符串,那就太好了.但如果这是唯一的原因,这是不必要的复杂,......

chq*_*lie 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);
}
Run Code Online (Sandbox Code Playgroud)

另请注意,您提出的替代方案不正确:您传递的错误长度为Atom_new().您应该传递sprintf或返回的字节数snprintf.这是一个改进版本:

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

  • @ a3f:我发布了一个更简单,更便携的解决方案,可以处理2s补码表示的不对称范围.它只假设"long"类型的最大范围大约为128位. (2认同)