일
KNK Chap.3 (3.1) 본문
3 서식 입출력 Formatted Input/Output
서식 입출력을 지원하는 함수인 scanf와 printf는 C에서 가장 자주 쓰이는 함수임.
이 둘은 아주 강력하지만 제대로 쓰기엔 조금 까다로움.
여기서 자세히 다루는건 아니고, 더 구체적인 설명은 Chap 22에서 다룸.
3.1 printf 함수 The printf Function
printf 함수는 서식 문자열 + 문자열의 특정 부분에 삽입된 값을 출력하는 기능으로 개발됨.
Ex.↓
result. ↓
즉, printf 함수는 서식 문자열 + 삽입되어야 하는 값을 출력할 때 호출해야 함.
printf(string, expr1, expr2, ...);
출력되는 값은 상수, 변수, 아니면 더 복잡한 표현식도 가능.
printf 함수를 한번 호출할 때, 정해진 출력값의 개수는 없음.
서식 문자열은 일반적 글자, %로 시작되는 변환 규격conversion specification 둘 다 포함 가능.
변환 규격은 출력될 때 채워져야 하는 값을 대신하는 기호나 텍스트의 일부임.
이런 기능을 하는 애들을 보통 플레이스 홀더placeholder라고 부름.
% 다음으로 나오는 정보는 내부 형식(이진수binary)변에서 출력 형식(문자character)으로
어떻게 값의 규격이 변환되는지 정함. 이게 변환 규격 이라는 명칭의 유래임.
예를 들어, %d는 printf 함수가 int 값을 이진수에서 십진수 문자열로 변환해 출력하는 규격을 정함.
%f는 float 값에 대해 마찬가지의 과정으로 규격을 정함.
서식 문자열 안의 일반적 문자들은 생긴 그대로 출력이 됨.
변환 규격은 출력되어야 하는 값으로 변환되어 출력이 됨.
다음의 예제 확인
int i, j;
float x, y;
i = 10;
j = 20;
x = 43.2892f;
y = 5527.0f;
printf("i = %d, j = %d, x = %f, y = %f\n", i, j, x, y);
여기서 printf 함수를 호출하면 아래와 같은 결과가 출력될 것임
i = 10, j = 20, x = 43.289200, y = 5527.000000
아까 말한 것처럼 변환 규격들은 출력해야 하는 값으로 변환되어 순서대로 출력됨.
[!!!] C 컴파일러는 변환 규격의 개수가 출력 값의 개수와 같은지 체크하지 않음.
아래의 printf 함수 호출을 보면 변환 규격이 출력되어야 하는 값보다 더 많음.
printf("%d %d\n", i); /*** WRONG ***/
위의 printf는 i 값은 맞게 출력하고, 두번째로는 의미 없는 정수값을 출력할 것임.
변환 규격의 개수가 출력 값보다 적어도 비슷한 문제가 발생함.
printf("%d\n", i, j); /***WRONG***/
이 경우 printf는 i 값만 출력하고 j 값은 출력하지 않음.
게다가, 컴파일러는 출력되는 값의 유형에 변환 규격이 적절한지 체크하지 않음.
만약 프로그래머가 잘못된 규격을 써도, 프로그램은 그냥 실행되어 의미없는 출력값을 낼 뿐임.
다음과 같이 int 변수 i와 float 변수 x가 잘못된 순서로 적힌 printf 호출을 가정하면
printf("%f %d\n", i, x); /*** WRONG ***/
printf 는 서식 문자열의 지시를 따르기 때문에, float 값 출력 후 int 값을 출력할 것임.
둘다 의미 없는 출력값일테지만.
변환 규격 Conversion Specification
변환 규격은 프로그래머에게 출력값에 대한 다양한 통제권을 주지만 읽기 어렵고 복잡함.
사실, 변환 규격을 완벽히 설명하기란 너무 힘든 일임. 대신, 변환 규격의 중요 기능을 살펴 보겠음.
변환 규격의 형식을 일반적으로 정리해보자면, %m.pX나 %-m.pX 같은 형식이 됨.
여기서 m과 p는 정수 상수이고, X는 문자인데, 여기서 m과 p는 옵션 사항임.
예를 들어 변환 규격 %10.2f에서 m은 10이고, p는 2이고, X는 f임.
%10f에서 m은 10이고 p는 없고 X는 f임. %.2f에서 m은 없고 p는 2이고 X는 f임.
m은 최소 범위 너비minimum field width의 약어로, 출력할 글자의 최소 개수를 정함.
출력될 값이 필요로 하는 글자가 m 개보다 작다면, 그 값은 주어진 범위에 있는 것임.
그러면, 여분의 빈 칸이 값의 앞에 옴. 예를 들어, 규격 %4d는 123을 ●123으로 출력함.
여기서 ● 기호는 빈칸(스페이스 부호)을 의미함. 앞으로도 그 의미로 쓰겠음.
출력될 값이 필요로 하는 글자가 m개보다 많다면, 자동으로 범위를 필요한 만큼 넓힘.
예를 들어 규격 %4d가 12345를 출력해야 하면, 빈칸이 없어지고 12345 로 출력될 것임.
-(minus) 기호를 m 앞에 쓰면 왼쪽 자리맞춤left justification이 일어남.
규격 %-4d로 123을 출력하면 123●이 출력될 것임.
p는 정확도precision의 약어로, X, 즉 변환 규격자conversion specifier에 따라 달라짐.
변환 규격자는 값이 출력되기 전에 어떤 방식의 변환이 적용될지 결정함.
가장 자주 사용되는 숫자의 변환 규격자 ↓
○ d : 십진수 형식으로 정수를 출력. p는 출력할 숫자의 최소 자리수를 의미함.
만약 필요시 숫자 시작 부분에 추가적으로 0이 들어올 수 있음.
만약 p가 포함되지 않으면, 그 값은 1이라고 가정함. 즉, %d와 %.1d는 같은 것임.
○ e : 소수를 지수 형식(과학적 기수법*)으로 출력.
*과학적 기수법: 너무 크거나 너무 작은 숫자들을 십진법으로 표현하는 기수법
p는 소수점 이하 자리 수를 얼마만큼 출력할 건지 결정함. 기본값default은 6자리임.
p가 0이면 소수점 이하는 출력되지 않음.
○ f : 소수를 지수 표현 없이 고정 소수점fixed decimal* 형식으로 출력함.
고정 소수점*: 소수점을 미리 정해진 위치에 자리하도록 설정한 형식
p는 e 규격자와 같은 의미를 가짐.
○ g : 소수를 숫자의 크기에 따라 고정 소수점이나 지수 형식으로 출력함.
p는 출력될 최대 유효 숫자 자리수를 결정함(소수점 이하 자리수가 아님).
f 규격자와 달리 0을 출력하지 않고, 출력할 소수점 이하 자리수가 없으면 소수점도 출력 안함.
또한, 숫자의 사이즈를 예측할 수 없거나 사이즈 범위가 너무 다양할 때 쓰기 좋음.
적당히 크거나 작은 숫자를 출력할 때, g 규격자는 고정 소수점 형식을 이용함.
아주 크거나 작은 숫자를 출력할 때는 지수 형식을 이용하여 숫자 길이를 짧게 함.
위 규격자 말고도 다양한 규격자들이 있음. 궁금하면 22.3 단원 참고.
PROGRAM: printf를 이용한 숫자 서식 Using printf to Format Numbers
다양한 형식을 이용해 정수와 실수를 출력하는 프로그램.
program name: tprintf.c
부호 |는 그냥 서식 문자열이 출력될 때 얼마나 많은 칸을 잡아먹는지 보여주기 위해 썼음.
%나 \n 처럼 출력 시 특별한 의미가 있는 부호는 아님. 프로그램 출력값은 아래와 같음.
이 프로그램에 쓰인 변환 규격을 자세히 살펴보자면 ↓
○ %d: i를 십진수 형태로 출력, 최소 출력 자리만 차지.
○ %5d: i를 십진수 형태로 출력, 최소 5칸 차지. → i는 2칸이라 빈 칸 3개 i 앞에 추가.
○ %-5d: i를 십진수 형태로 출력, 왼쪽 정렬로 최소 5칸 차지. → 빈 칸 3개 i 뒤에 추가.
○ %5.3d: i를 십진수 형태로 출력, 최소 5칸 차지, 숫자 최소 3칸 차지. →빈 칸 2개 i 앞에 추가.
○ %10.3f: x를 고정 십진수 형태로 출력, 최소 10칸 차지, 소수점 이하 최소 3칸 차지.
→ x는 7칸이라(소수점 이전 3칸, 소수점 이후 3칸, 소수점 1칸) 빈칸 3개 x 앞에 추가.
○ %10.3e: x를 지수형으로 출력, 최소 10칸 차지, 소수점 이하 최소 3칸 차지.
→ x는 지수 포함 9칸을 소비하므로, 빈칸 1개 x 앞에 추가.
○ %-10g: x를 고정 십진수 형태나 지수형으로 출력, 왼쪽 정렬로 최소 10칸 차지.
→ 이 경우, printf는 고정 십진수 형태를 선택했음. 빈칸 4개 x 뒤에 추가.
확장 비트열 Escape Sequences
\n처럼 서식 문자열에서 자주 쓰는 코드는 확장 비트열escape sequence라고 함.
확장 비트열은 문자열이 컴파일러에 문제를 일으킬 수도 있는 문자* 또한 포함하게 해줌.
*: 출력되지 않는 제어 문자control character나 컴파일러가 특별히 여기는 문자(Ex. ").
7.3 단원에서 확장 비트열 리스트를 배울 수 있음. 지금은 대표적 예시를 배울 것임.
\a: Alert(bell) 경보(종소리)
\b: Backspace 백스페이스
\n: New line 새 줄
\t: Horizontal tab 수평 탭
확장 비트열은 서식 문자열 중 가장 먼저 실행됨.
\a는 출력하면 대부분의 기기에서 진짜 경보음이 남.
\b는 출력하면 커서가 커서가 한 칸 뒤로 감.
\n은 출력하면 커서가 다음 줄 첫 칸으로 감.
\t는 출력하면 커서가 한 탭 뒤로 감.
문자열은 개수 제한 없이 확장 비트열을 포함할 수 있음.
서식 문자열이 6개의 확장 비트열을 포함한 아래의 printf 예시를 보면
실행 시 다음과 같이 출력됨을 알 수 있음
+ 또 흔하게 쓰이는 확장 비트열은 \" 임. " 부호를 출력함.
" 부호는 문자열의 처음과 끝을 나타내는 문자이기 때문에, 확장 비트열 없이는 출력 불가함.
printf("\"Hello!\"");
이런 식으로 쓰면 됨.
그리고 문자열에서 \ 부호 하나만 쓰면 컴파일러가 확장 비트열의 시작으로 인식함.
출력하고 싶으면 \\ 이런 식으로 두 개를 이어 쓰면 됨.
printf("\\"); /* prints one \ character */
'C' 카테고리의 다른 글
KNK Chap.3 (Q&A) (0) | 2022.12.14 |
---|---|
KNK Chap.3 (3.2) (1) | 2022.12.14 |
KNK Chap.2 (2.8~Q&A) (0) | 2022.12.06 |
KNK Chap.2 (2.5~2.7) (0) | 2022.12.03 |
KNK Chap.2 (2.4) (0) | 2022.12.02 |