Putchar 함수와 printf 의 차이

c언어 책을 보던중 이해가 잘 가지 않은 부분이 있었습니다.( 열혈강의 c프로그래밍 - 윤성우 저- )

문자단위 입출력 함수가 존재하는 이유에 관해 설명하는 부분 이었는대, 본문 그대로 이렇게 쓰여있었습니다.

  • printf 함수와 scanf함수는 문자단위 입·출력 함수에 비해서 강력한 기능을 지닌다 …(중략)
    이 함수들(printf , scanf)이 진정 빛을 발할 때는 형식을 지정해서 출력 및 입력하는 경우이다.
    그러나 이렇게 강력한 기능을 지니는 함수들은 그에 따른 대가도 요구된다. 쉽게 말하면, 강력한
    기능을 지니는 만큼 요구되는 메로리공간도 크고 속도도 느리다는 뜻이다. (중략) -

  • 정말로 필요한 기능이 하나의 문자를 출력하는 것이라면 putchar 함수를 사용해야 한다. 만약에 printf함수를 사용한다면,
    파리를 잡기위해 박격포를 쏘는 격이 될 것이다. (중략) -

putchar함수와 getchar함수가 어떤 기능을 하는 함수인지는 파악을 했는대, 내부적으로 이 함수들이 printf 와 scanf와는 어떻게 다른지는 잘 모르겠내요.
‘파리를 잡기위해 박격포를 쏘는 격이 될것이다.’ 라는 비유처럼 두 함수(printf , scanf와 putchar , getchar)의 차이가 상당한가요?

네, 엄청난 차이가 있습니다. printf는 맨 처음에 오는 형식 문자열(format string)을 해석하는 작업을 수행합니다.
예를 들어 printf("%c", ‘a’) 를 수행할 때, "%c" 가 "문자 하나를 그대로 출력하라"라는 뜻임을 해석해내야 합니다. (그냥 저절로 되는게 아니라 이 역시 프로그램이 돌아가는 것입니다).

지금 막 배우시는 중이라면 차이가 와닫지 않으실 수도 있는데, 사실 형식 문자열은 초보자용 교재에서 다루는 것 이상으로 복잡한 형태를 이루는 경우가 많습니다. 해석 작업이 그리 쉬운 일이 아니죠.

더불어 환경이나 구현방식에 따라 printf는 내부에서 다른 함수를 연이어 수행하기 때문에, 함수 호출에 따른 시간 소모도 고려해야 합니다. 간략히 예를 보여드리면,

printf는 fprintf를 호출->fprintf는 vfprintf를 호출 -> vfprintf는 … -> …

물론, 워낙 빠른 요즘 시스템에선 단순히 문자 하나만을 출력하는데에 printf나 putchar나 거의 차이가 없을 것입니다.

아… 그런 차이점이 있었군요, 어렴풋 왜그런지는 대충 이해가 되는것 같습니다… 그러면 printf함수와 scanf함수가 형식을 지정해서 출력 및 입력하는 경우 진정한 빛을 발한다고 했는대, ‘형식을 지정해서 출력 및 입력한다는 것’ 이 자세히 어떤 특수한 경우 이길래 복잡한 이 두함수(printf , scanf)를 사용할시 더 용이하다는 것인가요?

복잡하게 설명하고 있는데, 간단히 말하면 '형식을 지정하여 출력’한다는 것은 엑셀에서 ‘셀 속성’ 지정해서 출력하는 거랑 별반 다를 바가 없습니다. 엑셀 아시죠? 왼쪽 정렬 가운데 정렬, 소수점 자리 지정 이런 거입니다. 예를 들면:

[code:ykps9i7q]
printf("%20s : %5d\n", "홍길동", 95);
printf("%20s : %5d\n", "이순신", 100);
printf("%20s : %5d\n", "유관순", 90);
printf("%20s : %5.2f\n", "평균", (90 + 95 + 100) / 3);
[/code:ykps9i7q]
위 코드는 대충 다음과 같은 내용을 화면에 출력합니다.

[code:ykps9i7q]
홍길동 : 95
이순신 : 100
유관순 : 90
평균 : 95.00
[/code:ykps9i7q]

printf를 사용하지 않는다면 다음과 같은 경우를 프로그래머가 일일히 처리해 주어야 합니다.
[list:ykps9i7q]
[:ykps9i7q] %20s 자리에 출력될 문자열의 길이를 구해서 남은 칸이 얼마인지 계산, 문자열을 출력한 후 그 너비만큼 공백으로 채워넣음[/:m:ykps9i7q]
[:ykps9i7q] %3d 자리에 출력될 정수의 자리수를 세어 남은 칸이 얼마인지 계산, 공백을 채워넣은 후에 정수를 출력[/:m:ykps9i7q]
[:ykps9i7q] %3.2f 자리에 출력될 부동소수점 수의 실수에서 두 자리 밑을 버리고, … 등등[/:m:ykps9i7q][/list:u:ykps9i7q]

어렵겠죠? 그래서 대부분의 언어에서는 C의 printf와 유사한 동작을 하는 기능을 제공합니다.

덧붙여 printf에서는 여기서 말한 정렬, 소수점 자리 지정 말고도 수많은 기능이 더 있습니다. 그래도 자주 쓰이는 건 이 정도라 볼 수 있죠.

[quote="mukka":rvnp086c]복잡하게 설명하고 있는데, 간단히 말하면 '형식을 지정하여 출력’한다는 것은 엑셀에서 ‘셀 속성’ 지정해서 출력하는 거랑 별반 다를 바가 없습니다.[/quote:rvnp086c]

우분투 포럼에서 엑셀 얘기를 꺼내고 있네요… 리브레오피스로 정정합니다. 8-)

그냥 간단히 말하면, printf는 vsprintf 이후 puts라고 보시면 됩니다.
vsprintf는 가변 갯수 매개변수를 처리하는 sprintf 이구요.
sprintf는 매개변수들을 형식화하여 문자열로 변환하는 함수에요
물론 실제로는 sprintf가 가변길이를 처리하고, vsprintf가 실제 문자열을 출력하지만 개념적으로 설명을 한 것이고요,
내부적으로는 sbprint등의 함수를 사용하고 있을 것입니다.
printf는 가변 갯수의 매개변수 처리, 변수 타입 변환, 출력 형태 꾸미기, 실제 문자열 출력의 기능이 합쳐져 있는 것이죠.
그러니까, printf의 실제코드는 putchar에 비교할 수 없을 정도로 크겠죠.

그러나, 실제로는 크기도, 속도도 차이를 거의 느낄 수 없습니다.

라이브러리가 통합되어 있어서, 컴파일한 바이너리에는 동적라이브러리 내에 존재하는 함수에 대한 참조 호출만 존재하기 때문이죠.
그리고 속도도 다른 백그라운드 프로그램들에 의해 CPU를 독점하지 못하기 때문에,
정확히 측정하기 힘듭니다.

'A’를 천만 번 출력하는 프로그램을 돌려본 결과, 두 개의 차이는 0.122초 차이가 났습니다.
물론 이도 앞서 말한 바와 같이 정확할 수 없습니다.
그러니까, 아주 많은 문자의 출력이나, 반복에 의해서만 차이가 느낄 정도로 날 뿐입니다.

하지만, 효율적인 프로그래밍의 습관은 중요한 것이고, 연산 중심적인 프로그램을 작성할 경우 이것이 누적되면 큰 차이를 보일 수 있습니다.
예를 들어, 슈퍼컴퓨터로 암호를 깨어 암호화의 안전성을 테스트하는 프로그램이나, 과학 시뮬레이션, 인공지능, 복잡한 게임 등의 프로그램에서는
아무래도 속도가 중요합니다.
그러니까, 효율적이면서도 명시적으로 소스를 작성하는 습관이 좋겠죠.

늦은 대댓들 죄송합니다;

두분이 올려주신 답변 덕분에 몰랏던 부분에 대해서 많이 배우고 보다 명쾌히 이해되는것 같내요, 좋은 답변 감사드립니다. :)