2012-12-14 2 views
0

printf() 메서드가 부호있는 또는 부호없는 정수를 출력하는 방법에 관한 질문이 있습니다. 어느 날 컴퓨터에서 십진수의 개념이 없다는 점을 감안할 때 이진 시퀀스를 인간이 이해할 수있는 십진수 시퀀스로 변환하는 것이 얼마나 어려워야 하는지를 생각했습니다.정수가 포함 된 printf() 이해

아래에는 관련 메서드가있는 printf() 메서드가 있습니다 (here). 내가 라이브러리 소스 코드를 읽기 싫어하는 한 가지있다

#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); 
} 

경우, 그것이 좀처럼 읽을 수 있다는 : 당신이 코멘트에서 볼 수 있듯이 나는 어떻게 printi() 작품에 대해 내가 할 수있는만큼을 이해하기 위해 노력했습니다. 하나의 문자와 설명이없는 변수 이름은 통증입니다.

간단한 방법으로 정수를 10 진수 문자열로 변환하는 방법을 정확히 설명해 주시겠습니까?

+3

하나의 글에 여러 질문이 게시되면 여러 게시물로 나눌 수 있습니다. –

+0

완료 (http://stackoverflow.com/questions/13878485/printing-multiple-integers-as-one-arbitrarily-long-decimal-string) . – Doddy

답변

0

내가 10을 기반으로하는 양의 정수를 변환 할 방법은 기본적으로이 뒤로 수를 출력하는 것을 제외하고

if (i == 0) 
    printf("0"); 
else while (i != 0) { 
    unsigned int j = i/10; 
    unsigned int digit = i - 10 * j; 
    printf("%c", digit + '0'); 
    i = j; 
} 

.

+0

그리고'<>'연산자가 C에 존재하지 않는다는 것을 제외하면 ... 기본적으로이 대답은 쓸모가 없습니다. –

+0

@ H2CO3가'! = '연산자를 수정했습니다. – kmkaplan

1

어쩌면 내가 템플릿 라이브러리 헤더를 너무 오랫동안 쳐다 보았을지도 모르지만 그 라이브러리 코드는 나에게 꽤 읽을 만해 보인다!

나머지 (기호를 둘러싼 저글링 등)를 이해하기가 쉽기 때문에 주 루프에 대해 설명하겠습니다. 오른쪽에서 우리가 한 번에 숫자 하나를 추출되어 일을 기본적으로 무엇을

while (u) 
{ 
    t = u % b; 

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

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

, 를 왼쪽으로. b == 10 (즉, 일반적인 경우는 %d 또는 %u)이라고 가정합니다. 모듈러스 연산자라고하는 % 연산자는 정수 나누기 후에 남은 나머지를 계산합니다. 처음으로 줄 t = u % b;이 실행되면 숫자 u을 10으로 나눈 값을 나머지로 남겨 두는 출력 문자열의 가장 오른쪽 숫자를 계산합니다. 숫자 u이 493 인 경우이를 10으로 나눈 나머지는 다음과 같습니다. 3, 가장 오른쪽 숫자)

t으로이 오른쪽 숫자를 추출한 후 if 문은이 숫자가 10 이상인 경우이 숫자를 "호출 할"것을 결정합니다. 이 픽스 업은 t을 조정하므로 '0'(숫자 '0'의 ASCII value, 48)이 다음 줄에 추가되면 결과는 'a'또는 'A'(~에서 시작하는 문자가됩니다. 10보다 큰 밑자리의 경우 16 진수 및 다른 숫자 생성).

다음 줄은 숫자를 버퍼에 씁니다. 의 가장 오른쪽 문자이 버퍼 (이 버퍼의 을 가리 키도록 초기에 초기화 된 것을 알 수 있습니다. 일반적으로 시작은 아님). 이어서 포인터 s은 다음 문자를 준비 할 때 한 문자 왼쪽으로 이동합니다.

다음 줄 u /= bu을 10으로 나누기 만하면 가장 오른쪽 숫자를 효과적으로 버립니다. (이것은 정수 나누기가 분수를 생성하지 않으므로 항상 작동합니다.) 그러면 다음 루프 반복을 처리 할 두 번째 맨 오른쪽 숫자가 열립니다. 린스, 반복하십시오. 루프가 남아 있지 않으면 루프가 마침내 중지됩니다 (조건 while (u)은 조건 while (u != 0)과 같습니다).

2

붙여 넣은 코드는 읽기가 어렵지 않습니다. 당신이 일찍 포기한 것 같아요. 잠시 음수의 가능성을 무시

printi() 루틴 :

  • 넓은 12 개 문자에 번호를 인쇄 할 버퍼를 작성하면 를 가리 키도록 문자 포인터 s을 설정의 끝이 버퍼 ** NULL-종료는 다음

그 다음 루틴이 들어가는 "왼쪽"포인터를 이동 한 문자 루프만큼 수가 남아> 0

  • MOD 10에 의하여 (즉, 10으로 분할하고 나머지를 가지고)이 s가 가리키는 숫자된다
    • 때문에 대한 AS ASCII 표현은
  • 다시 왼쪽으로 이동이
    • s 넣어
    • 번호를 자체/10으로 설정하십시오. 이 여기있는 유일한 까다로운 일이 음수에 대해 다루고 있습니다

    인쇄 한 이상의 숫자가있는 한

  • 반복 루프를 인쇄 한 숫자를 제거하지만 당신이 이해하는 경우 저장하는 방법을 음수 , 그것은 전혀 까다로울 필요가 없습니다.