了解printf()的整数带 [英] Understanding printf() with integers

查看:148
本文介绍了了解printf()的整数带的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个关于在的printf()方法打印整数如何,符号或无符号的问题。有一天,我发现自己想那一定是多么困难二进制序列转换成十进制数字,一个人能够理解的顺序,因为一台电脑没有小数的概念。

I have a question regarding how the printf() method prints integers, signed or unsigned. One day, I found myself thinking about how difficult it must be to convert a binary sequence into a sequence of decimal digits that a human can understand, given that a computer has no concept of decimal.

下面,我有一个的printf()方法(从的这里)。我试图理解,就像我能如何维护涂料()工作,因为你可以在评论中看到:

Below, I have a printf() method (from here) with its associated methods. I've tried to understand as much as I can about how printi() works, as you can see in the comments:

#define PAD_RIGHT 1
#define PAD_ZERO 2

#include <stdarg.h>

static void printchar(char **str, int c)
{
    extern int putchar(int c);

    if (str) {
        **str = c;
        ++(*str);
    }
    else (void)putchar(c);
}

static int prints(char **out, const char *string, int width, int pad)
{
    register int pc = 0, padchar = ' ';

    if (width > 0) {
        register int len = 0;
        register const char *ptr;
        for (ptr = string; *ptr; ++ptr) ++len;
        if (len >= width) width = 0;
        else width -= len;
        if (pad & PAD_ZERO) padchar = '0';
    }
    if (!(pad & PAD_RIGHT)) {
        for ( ; width > 0; --width) {
            printchar (out, padchar);
            ++pc;
        }
    }
    for ( ; *string ; ++string) {
        printchar (out, *string);
        ++pc;
    }
    for ( ; width > 0; --width) {
        printchar (out, padchar);
        ++pc;
    }

    return pc;
}

/* the following should be enough for 32 bit int */
#define PRINT_BUF_LEN 12

static int printi(char **out, int i, int b, int sg, int width, int pad, int letbase)
{
    /*
        i is the number we are turning into a string
        b is the base, i.e. base 10 for decimal
        sg is if the number is signed, i.e. 1 for signed (%d), 0 for unsigned (%u)

        By default, width and pad are 0, letbase is 97
    */

    char print_buf[PRINT_BUF_LEN];
    register char *s;
    register int t, neg = 0, pc = 0;
    register unsigned int u = i;

    if (i == 0)
    {
        print_buf[0] = '0';
        print_buf[1] = '\0';
        return prints(out, print_buf, width, pad);
    }

    if (sg && b == 10 && i < 0)
    {
        neg = 1;
        u = -i;
    }

    s = print_buf + PRINT_BUF_LEN - 1;
    *s = '\0';

    while (u)
    {
        t = u % b;

        if (t >= 10)
            t += letbase - '0' - 10;

        *--s = t + '0';
        u /= b;
    }

    if (neg)
    {
        if (width && (pad & PAD_ZERO))
        {
            printchar(out, '-');
            ++pc;
            --width;
        }
        else
            *--s = '-';
    }

    return pc + prints(out, s, width, pad);
}

static int print(char** out, const char* format, va_list args)
{
    register int width, pad;
    register int pc = 0;
    char scr[2];

    for (; *format != 0; ++format)
    {
        if (*format == '%')
        {
            ++format;
            width = pad = 0;

            if (*format == '\0')
                break;

            if (*format == '%')
                goto out;

            if (*format == '-')
            {
                ++format;
                pad = PAD_RIGHT;
            }

            while (*format == '0')
            {
                ++format;
                pad |= PAD_ZERO;
            }

            for (; *format >= '0' && *format <= '9'; ++format)
            {
                width *= 10;
                width += *format - '0';
            }

            if (*format == 's')
            {
                register char* s = (char*) va_arg(args, int);
                pc += prints(out, s ? s : "(null)", width, pad);
                continue;
            }

            if (*format == 'd')
            {
                pc += printi(out, va_arg(args, int), 10, 1, width, pad, 'a');
                continue;
            }

            if (*format == 'x')
            {
                pc += printi(out, va_arg(args, int), 16, 0, width, pad, 'a');
                continue;
            }

            if (*format == 'X')
            {
                pc += printi(out, va_arg(args, int), 16, 0, width, pad, 'A');
                continue;
            }

            if (*format == 'u')
            {
                pc += printi(out, va_arg(args, int), 10, 0, width, pad, 'a');
                continue;
            }

            if (*format == 'c')
            {
                /* char are converted to int then pushed on the stack */
                scr[0] = (char) va_arg(args, int);
                scr[1] = '\0';
                pc += prints(out, scr, width, pad);
                continue;
            }
        }
        else
        {
            out:
            printchar (out, *format);
            ++pc;
        }
    }

    if (out)
        **out = '\0';

    va_end(args);

    return pc;
}

int printf(const char *format, ...)
{
        va_list args;

        va_start( args, format );
        return print( 0, format, args );
}

如果有一件事我恨读库源$ C ​​$ C,那就是它几乎没有可读性。有一个字符,并且没有注释变量名来解释他们是一种痛苦。

If there's one thing I hate about reading library source code, it's that it's hardly ever readable. Variable names with one character and no comment to explain them are a pain.

能否请您解释一下,在一个简单的方式,究竟是什么方法做的整数转换成十进制数字组成的字符串?

Can you please explain, in a simple way, what exactly the method is doing to convert an integer into a string of decimal digits?

推荐答案

您已经粘贴的code不是难以阅读。我怀疑自己可能早放弃了。

The code you've pasted is not difficult to read. I suspect you may have given up early.

忽略潜在的片刻负数,这个维护涂料()常规:

Ignoring the potential for a negative number for a moment, this printi() routine:


  • 创建一个缓冲区来打印成数,12个字符的宽度

  • 设置一个字符指针取值指向的结束的缓冲区中
    ** NULL-终止它,然后移动鼠标指针的一个字符,左

  • creates a buffer to print the number into, 12 characters wide
  • sets a character pointer s to point to the end of that buffer ** NULL-terminates it, then moves the pointer one character to the "left"

然后,例行程序进入一个循环,只要数保持> 0

Then the routine enters a loop, for as long as the number remains > 0


  • MOD 10(即除以10取余)


    • 这成为该的字符S 指向,所以ASCII重新presentation被放在那里

    • MOD by 10 (that is, divide by 10 and take the remainder)
      • this becomes the digit that s is pointing to, so the ASCII representation is put there

      • 取值移动到左侧再次

      • s is moved to the left again

      这里唯一棘手的事情是负数处理,但如果你了解负数存储,它不是真正棘手的。

      The only tricky thing here is the dealing with negative numbers, but if you understand how negative numbers are stored, it's not really tricky at all.

      这篇关于了解printf()的整数带的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆