printf - 기능 살펴보기

2021. 2. 8. 01:0242seoul/printf

우리는 c언어를 처음 배우면서 기초로 터미널에 혹은 개발자 도구(visual stduio, visual code)를 사용해서 printf를 사용하여 "hello world"를 입력하고 화면에 출력하는 것을 실습해본다.

 

그러면서 자연스럽게 함수에 대해 배우고 함수의 기능 등 점점 printf의 내부는 어떻게 돌아갈까?에 대한 의문을 잊은채로 다른 것을 만들기 시작한다.

 

그래서 나는 "서울42"라는 우연한 기회에 정말 운명같이 우리가 아무 개념없이 써버린 printf의 구현을 만나버렸다... 구현하는데 3개월이 걸렸지만..

알고난뒤 나는 너무 놀랍고 가치있는 경험이라고 말할 정도로 다들 해보라 추천하고 싶었다. 그래서 이렇게 정리해서 올리려고 한다.

 

 

<여기서 printf 기능은 %c, %d, %%, %string, 16진법 출력을 구현하는 것으로 제한한다. 그 외 여러 기능들에 있어서 독자가 직접 한번 구현해보기를 추천한다. 앞의 구현 과정을 보면 아 이렇게 하면 되겠구나 하는 감이 올것이다.>

 

1. printf

단순히 printf만을 그냥 설명하자면 pritnf도 결국 함수이며, printf내부 여러함수 덩어리들이 모여 printf를 구성한다.

 

먼저 printf의 서식지정자를 중심으로 기능을 살펴보자!

 

----------------------------------------------------------------------------------------------------------------------------

// 정수
printf("%u\n", 10); // 10: 부호 없는 10진 정수
printf("%d\n", -20); // -20: 부호 있는 10진 정수
printf("%i\n", -20); // -20: 부호 있는 10진 정수
printf("%o\n", 071); // 71: 부호 없는 8진 정수
printf("%x\n", 0xF1); // f1: 부호 없는 16진 정수(소문자)
printf("%X\n", 0xF1); // F1: 부호 없는 16진 정수(대문자)

// long, long long.정수
printf("%lu\n", ULONG_MAX); // 4294967295: 부호 없는 long
printf("%ld\n", LONG_MAX); // 2147483647: 부호 있는 long
printf("%llu\n", ULLONG_MAX); // 18446744073709551615: 부호 없는 long long
printf("%lld\n", LLONG_MAX); // 9223372036854775807: 부호 있는 long long

// 실수
printf("%f\n", 1.2f); // 1.200000: 실수를 소수점으로 표기(소문자)
printf("%F\n", 1.2f); // 1.200000: 실수를 소수점으로 표기(대문자)
printf("%e\n", 1.2f); // 1.200000e+00: 실수 지수 표기법 사용(소문자)
printf("%E\n", 1.2f); // 1.200000E+00: 실수 지수 표기법 사용(대문자)
printf("%g\n", 1.2f); // 1.2: %f와 %e 중에서 짧은 것을 사용(소문자)
printf("%G\n", 1.2f); // 1.2: %F와 %E 중에서 짧은 것을 사용(대문자)
printf("%a\n", 1.2f); // 0x1.3333340000000p+0: 실수를 16진법으로 표기(소문자)
printf("%A\n", 1.2f); // 0X1.3333340000000P+0: 실수를 16진법으로 표기(대문자)

printf("%Lf", LDBL_MAX); // 생략: long double
printf("%Le", LDBL_MAX); // 1.797693e+308: long double

// 문자, 문자열
printf("%c\n", 'a'); // a: 문자
printf("%s\n", "Hello, world!"); // Hello, world!: 문자열

// 포인터
int num1;
void *ptr = &num1;
printf("%p\n", ptr); // 008BFB6C: 포인터의 메모리 주소
                               // 0x8bfb6c: 리눅스, OS X에서는 앞에 0x가 붙고, A~F는 소문자로 출력. 
                               // 높은 자릿수의 0은 생략

// % 기호
printf("%%\n");      // %: % 기호 출력

 

----------------------------------------------------------------------------------------------------------------------------

 

서식지정자를 살펴보았으면 이번에는 printf를 사용할 때 플래그, 폭, 정밀도, 길이를 조합해서 사용한 적이 있을 것이다. 

각 기능 별로 살펴보자

printf는 괄호 안의 기능을 다음 순으로 해석한뒤 출력의 형식을 정해준다. 

%[플래그][폭][.정밀도][길이]서식지정자

 

각 기능을 적용하면 어떻게 출력 되는지 한번 살펴보자.(근데 이쯤 되니까 코딩도장분 에꼴 42 출신이신가 싶은 의심이 드네)

 

%d에 폭을 지정해보면 다음과 같이 출력이 된다.

 

입력

printf("%6d\n", 20); // %d의 출력 폭을 6칸으로 지정
printf("%6d\n", 2000); // %d의 출력 폭을 6칸으로 지정

출력

↓ 4칸 공백
    20
  2000
↑ 2칸 공백

 

----------------------------------------------------------------------------------------------------------------------------

이번에는 폭과 플래그를 함께 써보고, 다음과 같이 폭 앞에 0을 넣으면 남는 공간에는 공백 대신 0으로 채우겠습니다.

 

입력

printf("%06d\n", 20);      // 출력 폭을 6칸으로 지정, 남는 공간은 0으로 채움
printf("%06d\n", 2000);    // 출력 폭을 6칸으로 지정, 남는 공간은 0으로 채움

폭 6칸, 남는 공간을 0으로 채우도록 했음으로 20 앞에는 0이 4개, 2000 앞에는 0이 2개 채워집니다.

출력

↓ 0이 4개 채워짐
000020
002000
↑ 0이 2개 채워짐

----------------------------------------------------------------------------------------------------------------------------

 

 

플래그 부분을 공백으로 지정하면 양수일때는 부호를 출력하지 않고 공백으로 표시하고, 음수일 때는 -부호를 출력합니다.

그리고 플래그를 +로 지정하면 양수일 때는 +부호, 음수일 때는 -부호를 출력합니다.

입력

printf("% d\n", 10);     // 양수일 때는 부호를 출력하지 않고 공백으로 표시
printf("% d\n", -10);    // 음수일 때는 - 부호를 출력

printf("%+d\n", 200);    // 양수일 때는 + 부호 출력
printf("%+d\n", -200);   // 음수일 때는 - 부호 출력

출력

 10
-10
+200
-200

----------------------------------------------------------------------------------------------------------------------------

실수를 출력하는 %f, %e는 정밀도를 지정할 수 있습니다. 다음과 같이 %뒤에 .(점)과 숫자를 넣습니다.

정밀도란 소수를 출력할 경우 소수 몇번째까지 자리수를 출력할 것인지 정하는 것 입니다.

입력

printf("%.2f\n", 1.2f);    // 소수 둘째 자리까지 출력
printf("%.2e\n", 1.2f);    // 소수 둘째 자리까지 출력

출력

1.20
1.20e+00

----------------------------------------------------------------------------------------------------------------------------

실수에 플래그, 폭, 정밀도를 함께 지정하면 

입력

printf("%010.2f\n", 1.2f);    // 출력 폭은 10칸, 소수 둘째 자리까지 출력, 남는 공간은 0으로 채움
printf("%010.2e\n", 1.2f);    // 출력 폭은 10칸, 소수 둘째 자리까지 출력, 남는 공간은 0으로 채움

출력 폭은 10칸이고, 소수 둘째 자리까지 출력, 남는 공간에 0을 채우며, 단, 실수는 폭에 소수점과 e+까지 포함합니다.

출력

0000001.20
001.20e+00

----------------------------------------------------------------------------------------------------------------------------

8진수와 16진수를 출력하는 경우 #플래그를 사용하면 자동으로 0이나, 0x, 0X를 앞에 붙여 줍니다.

 

입력

printf("%#o\n", 0721);    // 8진수이면 앞에 0을 붙임

printf("%#x\n", 0xf1);    // 16진수 소문자 출력이면 앞에 0x를 붙임
printf("%#X\n", 0xf1);    // 16진수 대문자 출력이면 앞에 0X를 붙임

출력

0721
0xf1
0XF1

 

 

----------------------------------------------------------------------------------------------------------------------------

문자와 문자열도 출력 폭을 지정할 수 있습니다.

입력

printf("%20c\n", 'a');                // 출력 폭을 20칸으로 지정
printf("%20s\n", "Hello, world!");    // 출력 폭을 20칸으로 지정

출력

                   a
       Hello, world!

지금까지 알아본 서식 지정자, 플래그, 폭, 정밀도를 표로 정리한것으 보면 다음과 같다.

자료형별로 서식 지정자에 지정할 수 있는 길이이다.

출처: dojang.io/mod/page/view.php?id=736